#include "TradeWidget.h"
#include <cassert>
#include "softProj\settings.h"
#include "softProj\WarehousesWidget\warehouseItemWidget.h"
#include "../streams/ErrorStream.h"

extern KODIAK_DEBUG_STREAM KODIAK_DEBUG_COUT;

TradeTable::TradeTable(TradeWidget * parent, ETradeTableType tableType, bool onlyScienceIndependent) : QWidget(parent) {
    titleLabel_ = 0;
    tableWidget_ = 0;
    searchButton_ = 0;
    searchEdit_ = 0;

    tradeWidget_ = parent;	
	this->tableType_ = tableType;
	this->onlyScienceIndependent_ = onlyScienceIndependent;
}

void TradeTable::setTitle(QPushButton * titleLabel) {
    this->titleLabel_ = titleLabel;
}

void TradeTable::setTable(QTableWidget * tableWidget) {
    this->tableWidget_ = tableWidget;
	tableWidget_->verticalHeader()->setResizeMode(QHeaderView::Interactive);
}

void TradeTable::setSearchButton(QPushButton * searchButton) {
    this->searchButton_ = searchButton;
}

void TradeTable::setShowAllButton(QPushButton * showAllButton) {
    this->showAllButton_ = showAllButton;
}

void TradeTable::setSearchEdit(QLineEdit * searchEdit) {
    this->searchEdit_ = searchEdit;
}

void TradeTable::connectSignals() {
    bool isConnected = connect(searchButton_, SIGNAL(clicked()), this, SLOT(searchClickedSlot()));
    assert(isConnected);

    isConnected = connect(showAllButton_, SIGNAL(clicked()), this, SLOT(showAllClickedSlot()));
    assert(isConnected);

    isConnected = connect(tableWidget_, SIGNAL(cellClicked(int,int)), this, SLOT(cellClickedSlot(int, int)));
    assert(isConnected);    
}

void TradeTable::showAllClickedSlot() {
    clearFilteredContent();

	for (std::map<id_t, TradeItem *>::const_iterator it = rows_.begin(); it != rows_.end(); ++it) {
		insertItemIntoTable(it->second);
    }
}

void TradeTable::searchClickedSlot() {
    QString searchedString = searchEdit_->text();
    QRegExp rx(".*" + searchedString + ".*", Qt::CaseInsensitive);

    clearFilteredContent();

    ItemsVector matchedItems;

	for (std::map<id_t, TradeItem *>::const_iterator it = rows_.begin(); it != rows_.end(); ++it) {
		if (rx.exactMatch(it->second->name)) {
            matchedItems.push_back(it->second);
        }
    }

    for (ItemsVector::const_iterator it = matchedItems.begin(); it != matchedItems.end(); ++it) {
        insertItemIntoTable(*it);
    }
}

void TradeTable::insertItem(TradeItem * item) {
    insertItemIntoTable(item);
}

int TradeTable::insertItemIntoTable(TradeItem * item) {
	
	tableWidget_->setSortingEnabled(false);

    const int targetRow = tableWidget_->rowCount();
    tableWidget_->insertRow(targetRow);

	rows_.insert(std::make_pair(item->getWarehouseItem().id, item));

	const warehouse_item_status & itemStatus = item->getWarehouseItem();

	WarehouseItemWidget * itemWidget = new WarehouseItemWidget(tableWidget_, itemStatus, true);

	for (warehouse_item_status::parameters_list_t::const_iterator paramIt = itemStatus.parameters.begin(); paramIt != itemStatus.parameters.end(); ++paramIt) {
		if (!onlyScienceIndependent_ || (onlyScienceIndependent_ && paramIt->scienceIndependent)) {
			itemWidget->addParameter(*paramIt);
		}
	}

	tableWidget_->setRowHeight(targetRow, itemWidget->height());
	tableWidget_->setCellWidget(targetRow, 0, itemWidget);	

	bool connected = connect(itemWidget, SIGNAL(clickedSignal(const warehouse_item_status &)), this, SLOT(itemClickedSlot(const warehouse_item_status &)));
	assert(connected && "Signals not connected");
    
	tableWidget_->setSortingEnabled(true);

    return targetRow;
}

void TradeTable::addCount(int row, unsigned long long working, unsigned long long damaged) {
	WarehouseItemWidget * tableItem = dynamic_cast<WarehouseItemWidget *>(tableWidget_->cellWidget(row, 0));

	if (tableItem == NULL) {
		KODIAK_DEBUG_COUT << "Table item is NULL in void TradeTable::addCount(int row, unsigned long long working, unsigned long long damaged)";
		return;
	}

	unsigned long oldWorking = tableItem->getWorking();
	unsigned long oldDamaged = tableItem->getDamaged();

	tableItem->setItemCount(oldWorking + working, oldDamaged + damaged);
}

void TradeTable::removeCount(int row, unsigned long long working, unsigned long long damaged) {
	WarehouseItemWidget * tableItem = dynamic_cast<WarehouseItemWidget *>(tableWidget_->cellWidget(row, 0));

	if (tableItem == NULL) {
		KODIAK_DEBUG_COUT << "Table item is NULL in void TradeTable::addCount(int row, unsigned long long working, unsigned long long damaged)";
		return;
	}

	unsigned long oldWorking = tableItem->getWorking();
	unsigned long oldDamaged = tableItem->getDamaged();

	tableItem->setItemCount(oldWorking - working, oldDamaged - damaged);
}

void TradeTable::clearFilteredContent() {
    for (int i = tableWidget_->rowCount() - 1; i >= 0; --i) {
        tableWidget_->removeRow(i);
    }    
}

void TradeTable::removeRow(int row) {
	tableWidget_->removeRow(row);
}

void TradeTable::clearAllContent() {
    clearFilteredContent();

	for (std::map<id_t, TradeItem *>::iterator it = rows_.begin(); it != rows_.end(); ++it) {
		delete it->second;
	}

	rows_.clear();
}

void TradeTable::cellClickedSlot(int row, int col) {
    TradeItem * itemRow = findItemRow(row, col);

	if (itemRow == NULL) {
		KODIAK_DEBUG_COUT << "Item widget is NULL in void TradeTable::cellClickedSlot(int row, int col)";
		return;
	}

    cellClicked(itemRow);    
}

void TradeTable::cellClicked(TradeItem * item) {
	switch (tableType_) {
	case TRADE_TABLE_OWNED:
		tradeWidget_->ownedItemClicked(item);
		break;
	case TRADE_TABLE_OWNED_OFFERS:
		tradeWidget_->ownedOfferClicked(item);
		break;
	case TRADE_TABLE_ENEMY:
		tradeWidget_->enemyItemClicked(item);
		break;
	case TRADE_TABLE_ENEMY_OFFERS:
		tradeWidget_->enemyOfferClicked(item);
		break;

	}
}

TradeItem * TradeTable::findItemById(unsigned long id) {
    if (rows_.find(id) != rows_.end()) {
        return rows_[id];
    }
    else {
        return 0;
    }
}

TradeItem * TradeTable::findItemRow(int row, int col) {
	WarehouseItemWidget * itemWidget = dynamic_cast<WarehouseItemWidget *>(tableWidget_->cellWidget(row, 0));
		
	if (itemWidget == NULL) {
		KODIAK_DEBUG_COUT << "Table item is NULL in TradeItem * TradeTable::findItemRow(int row, int col)";
		return 0;
	}
		
	id_t id = itemWidget->getItemId();

    if (rows_.find(id) != rows_.end()) {
        return rows_[id];
    }
    else {
        return 0;
    }
}

void TradeTable::removeRowAndItem(TradeItem * item, int row) {
	rows_.erase(item->getWarehouseItem().id);
	removeRow(row);
}

int TradeTable::findRowOfItem(unsigned long id) {
	int rowCount = tableWidget_->rowCount();

	for (int row = 0; row < rowCount; ++row) {
		WarehouseItemWidget * itemWidget = dynamic_cast<WarehouseItemWidget *>(tableWidget_->cellWidget(row, 0));

		if (itemWidget == NULL) {
			KODIAK_DEBUG_COUT << "Table item is NULL in TradeItem * TradeTable::findItemRow(int row, int col)";
			return -1;
		}

		int inspectedId = itemWidget->getItemId();

		if (inspectedId == id) {
			return row;
		}
	}
	 
	return -1;
}

void TradeTable::itemClickedSlot(const warehouse_item_status & item) {
	int row = findRowOfItem(item.id);
	TradeItem * tradeItem = findItemById(item.id);

	if (tradeItem == NULL) {
		KODIAK_DEBUG_COUT << "Trade item is NULL in void TradeTable::itemClickedSlot(const warehouse_item_status & item)";
		return;
	}

	cellClicked(tradeItem);
}

std::map<id_t, TradeItem *>::const_iterator TradeTable::storageBegin() {
	return rows_.cbegin();
}

std::map<id_t, TradeItem *>::const_iterator TradeTable::storageEnd() {
	return rows_.cend();
}