/**
TwitStreet - Twitter Stock Market Game
Copyright (C) 2012 Engin Guller (bisanthe@gmail.com), Cagdas Ozek (cagdasozek@gmail.com)
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
**/
package com.twitstreet.market;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Queue;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import org.apache.log4j.Logger;
import com.google.inject.Inject;
import com.google.inject.Singleton;
import com.twitstreet.db.base.DBConstants;
import com.twitstreet.db.base.DBMgr;
import com.twitstreet.db.data.Stock;
import com.twitstreet.db.data.TransactionRecord;
import com.twitstreet.db.data.User;
@Singleton
public class TransactionMgrImpl implements TransactionMgr {
private static final int TRANSACTION_INVERTAL_SEC = 30;
@Inject
DBMgr dbMgr;
private static Logger logger = Logger.getLogger(TransactionMgrImpl.class);
LinkedList<TransactionRecord> currentTransactions = new LinkedList<TransactionRecord>();
private static final String ADD_TRANSACTION_QUERY = "INSERT INTO transactions(user_id,stock, amount, t_action,t_date) values(?, ?, ?, ?, now())";
private static final String UPDATE_TRANSACTION_QUERY = "update transactions set amount = amount + ?, t_date = now() where user_id = ? and stock = ? and t_action = ? and timestampdiff(second, t_date, now()) < " + TRANSACTION_INVERTAL_SEC;
private static final String GET_CURRENT_TRANSACTIONS_QUERY = "select u.id as userId, u.userName as userName, s.id as stockId, s.name as stockName, t.t_action as transactionOperation, t.amount as transactionAmount, t.t_date as transactionDate from transactions t, stock s, users u where t.user_id = u.id and t.stock = s.id order by t.t_date desc limit ?";
private static final String GET_USER_TRANSACTIONS_QUERY = "select u.id as userId, u.userName as userName, s.id as stockId, s.name as stockName, t.t_action as transactionOperation, t.amount as transactionAmount, t.t_date as transactionDate from transactions t, stock s, users u where t.user_id = u.id and t.stock = s.id and t.user_id = ? order by t.t_date desc limit ?";
private static final String GET_STOCK_TRANSACTIONS_QUERY = "select u.id as userId, u.userName as userName, s.id as stockId, s.name as stockName, t.t_action as transactionOperation, t.amount as transactionAmount, t.t_date as transactionDate from transactions t, stock s, users u where t.user_id = u.id and t.stock = s.id and s.id = ? order by t.t_date desc limit ?";
private static LinkedList<TransactionRecord> transactionCache = new LinkedList<TransactionRecord>();
@Override
public void recordTransaction(User user, Stock stock, int amount,
int operation) {
Connection connection = null;
PreparedStatement ps = null;
try {
connection = dbMgr.getConnection();
ps = connection.prepareStatement(UPDATE_TRANSACTION_QUERY);
ps.setInt(1, amount);
ps.setLong(2, user.getId());
ps.setLong(3, stock.getId());
ps.setInt(4, operation);
int rowsUpdated = ps.executeUpdate();
if (rowsUpdated == 0) {
ps.close();
ps = connection.prepareStatement(ADD_TRANSACTION_QUERY);
ps.setLong(1, user.getId());
ps.setLong(2, stock.getId());
ps.setInt(3, amount);
ps.setInt(4, operation);
ps.execute();
}
TransactionRecord tr = new TransactionRecord();
tr.setStockId(stock.getId());
tr.setStockName(stock.getName());
tr.setUserId(user.getId());
tr.setUserName(user.getUserName());
tr.setOperation(operation);
tr.setAmount(amount);
tr.setDate(Calendar.getInstance().getTime());
synchronized (transactionCache) {
int existing = transactionCache.indexOf(tr);
if(existing < 0){
transactionCache.addFirst(tr);
}
else{
TransactionRecord existingTransaction = transactionCache.get(existing);
if( TimeUnit.MILLISECONDS.toSeconds(tr.getDate().getTime() - existingTransaction.getDate().getTime()) < TRANSACTION_INVERTAL_SEC){
existingTransaction = transactionCache.remove(existing);
tr.setAmount(tr.getAmount() + existingTransaction.getAmount());
transactionCache.addFirst(tr);
}
else{
transactionCache.addFirst(tr);
}
}
if(transactionCache.size() > 10){
transactionCache.removeLast();
}
}
} catch (SQLException ex) {
logger.error(DBConstants.QUERY_EXECUTION_FAIL + ps.toString(), ex);
} finally {
dbMgr.closeResources(connection, ps, null);
}
}
@Override
public List<TransactionRecord> getCurrentTransactions()
{
return transactionCache;
}
@Override
public List<TransactionRecord> getCurrentTransactionsFromDb() {
ArrayList<TransactionRecord> transactionRecordList = new ArrayList<TransactionRecord>();
Connection connection = null;
PreparedStatement ps = null;
ResultSet rs = null;
try {
connection = dbMgr.getConnection();
ps = connection.prepareStatement(GET_CURRENT_TRANSACTIONS_QUERY);
ps.setInt(1, TransactionMgr.CURRENT_TRANSACTION_LIMIT);
rs = ps.executeQuery();
while(rs.next()){
TransactionRecord transactionRecord = new TransactionRecord();
transactionRecord.getDataFromResultSet(rs);
transactionRecordList.add(transactionRecord);
}
} catch (SQLException ex) {
logger.error(DBConstants.QUERY_EXECUTION_FAIL + ps.toString(), ex);
} finally {
dbMgr.closeResources(connection, ps, rs);
}
return transactionRecordList;
}
@Override
public List<TransactionRecord> queryTransactionRecord(long userId) {
ArrayList<TransactionRecord> transactionRecordList = new ArrayList<TransactionRecord>();
Connection connection = null;
PreparedStatement ps = null;
ResultSet rs = null;
try {
connection = dbMgr.getConnection();
ps = connection.prepareStatement(GET_USER_TRANSACTIONS_QUERY);
ps.setLong(1, userId);
ps.setInt(2, TransactionMgr.CURRENT_TRANSACTION_LIMIT);
rs = ps.executeQuery();
while(rs.next()){
TransactionRecord transactionRecord = new TransactionRecord();
transactionRecord.getDataFromResultSet(rs);
transactionRecordList.add(transactionRecord);
}
} catch (SQLException ex) {
logger.error(DBConstants.QUERY_EXECUTION_FAIL + ps.toString(), ex);
} finally {
dbMgr.closeResources(connection, ps, rs);
}
return transactionRecordList;
}
@Override
public List<TransactionRecord> queryTransactionRecordByStock(long stockId) {
ArrayList<TransactionRecord> transactionRecordList = new ArrayList<TransactionRecord>();
Connection connection = null;
PreparedStatement ps = null;
ResultSet rs = null;
try {
connection = dbMgr.getConnection();
ps = connection.prepareStatement(GET_STOCK_TRANSACTIONS_QUERY);
ps.setLong(1, stockId);
ps.setInt(2, TransactionMgr.CURRENT_TRANSACTION_LIMIT);
rs = ps.executeQuery();
while(rs.next()){
TransactionRecord transactionRecord = new TransactionRecord();
transactionRecord.getDataFromResultSet(rs);
transactionRecordList.add(transactionRecord);
}
} catch (SQLException ex) {
logger.error(DBConstants.QUERY_EXECUTION_FAIL + ps.toString(), ex);
} finally {
dbMgr.closeResources(connection, ps, rs);
}
return transactionRecordList;
}
}