package ee.ut.math.tvt2008.salessystem.ui.model;


import org.apache.log4j.Logger;

import ee.ut.math.tvt2008.salessystem.domain.controller.SalesDomainController;
import ee.ut.math.tvt2008.salessystem.domain.controller.VerificationFailedException;
import ee.ut.math.tvt2008.salessystem.domain.controller.impl.SalesDomainControllerImpl;
import ee.ut.math.tvt2008.salessystem.domain.data.Client;
import ee.ut.math.tvt2008.salessystem.domain.data.Sale;
import ee.ut.math.tvt2008.salessystem.domain.data.SoldItem;
import ee.ut.math.tvt2008.salessystem.domain.data.StockItem;
import org.hibernate.Transaction;

/**
 * Main model. Contains warehouse, current purchase, purchase history and client models.
 */
public class SalesSystemModel {

    private static final Logger log = Logger.getLogger(SalesSystemModel.class);

    // warehouse model
    private StockTableModel warehouseTableModel;
    // current shopping cart model
    private CurrentPurchaseTableModel currentPurchaseTableModel;
    // puchase history model
    private PurchaseHistoryTableModel purchaseHistoryTableModel;
    // puchase history details model
    private PurchaseInfoTableModel purchaseInfoTableModel;
    // client model
    private ClientTableModel clientTableModel;
    private Client currentClient;
    private final SalesDomainController domainController;

    /**
     * CHANGED 5-th praks
     * Construct application model.
     * @param domainController Sales domain controller.
     */
    public SalesSystemModel(SalesDomainController domainController) {
        this.domainController = domainController;
        warehouseTableModel = new StockTableModel(((SalesDomainControllerImpl) domainController).getSession());
        currentPurchaseTableModel = new CurrentPurchaseTableModel();
        clientTableModel = new ClientTableModel(((SalesDomainControllerImpl) domainController).getSession());
        purchaseHistoryTableModel = new PurchaseHistoryTableModel();
        purchaseInfoTableModel = new PurchaseInfoTableModel();

        // populate stock model with data from the warehouse
        warehouseTableModel.populateWithData(domainController.loadWarehouseState());
        // populate client model
        clientTableModel.populateWithData(domainController.loadAllClients());
        // populate purchase history model
        purchaseHistoryTableModel.populateWithData(domainController.loadPurchaseHistory());
    }

    /**
     * @return warehouse model
     */
    public StockTableModel getWarehouseTableModel() {
        return warehouseTableModel;
    }

    /**
     * @return current purchase model
     */
    public CurrentPurchaseTableModel getCurrentPurchaseTableModel() {
        return currentPurchaseTableModel;
    }

    /**
     * @return purchase history model
     */
    public PurchaseHistoryTableModel getPurchaseHistoryTableModel() {
        return purchaseHistoryTableModel;
    }

    /**
     * @return purchase history detail model
     */
    public PurchaseInfoTableModel getPurchaseInfoTableModel() {
        return purchaseInfoTableModel;
    }

    public ClientTableModel getClientTableModel() {
        return clientTableModel;
    }

    /**
     * Set currently selected client.
     */
    public void setCurrentClient(Client currentUser) {
        this.currentClient = currentUser;
    }

    /**
     * @return currently selected client
     */
    public Client getCurrentClient() {
        return currentClient;
    }

    /**
     * Load purchase info for specified sale.
     * @param id sale id
     */
    public void updatePurchaseInfoDataModel(Long id) {
     
        Sale newSale = domainController.findSaleInfo(id);

        if (newSale != null) {
            this.purchaseInfoTableModel.setSale(newSale);
        }

        purchaseInfoTableModel.fireTableDataChanged();
        log.info(this.purchaseInfoTableModel.getSale().getSoldItems().size() + " sold items updated in the info view");
    }

    /**
     * Reload purchase history from database.
     */
    public void updatePurchaseHistoryDataModel() {
        purchaseHistoryTableModel.populateWithData(domainController.loadPurchaseHistory());
        purchaseHistoryTableModel.fireTableDataChanged();
    }

    /**
     * Save current purchase, and reload history.
     * @throws VerificationFailedException
     */
    public void submitCurrentPurchase() throws VerificationFailedException {
        domainController.submitCurrentPurchase(getCurrentPurchaseTableModel().getStockItems(), getCurrentClient());
        getCurrentPurchaseTableModel().clear();
        updatePurchaseHistoryDataModel();
        warehouseTableModel.fireTableDataChanged();
    }

    public void addStockItem(StockItem stockItem) {
        ((SalesDomainControllerImpl) domainController).addStockItem(stockItem);
        warehouseTableModel.populateWithData(domainController.loadWarehouseState());
        warehouseTableModel.fireTableDataChanged();
    }

    public void addClient(Client client) {
        ((SalesDomainControllerImpl) domainController).addClient(client);
        clientTableModel.populateWithData(domainController.loadAllClients());
        clientTableModel.fireTableDataChanged();
    }

    public void deleteClient(Client selectedClient) {
        if(selectedClient!=null){
            try {
                Transaction tx = ((SalesDomainControllerImpl) this.domainController).getSession().beginTransaction();
                for (Sale sale : domainController.loadPurchaseHistory()) {
                    if(sale.getClient()!=null)
                    if(sale.getClient().getId() == selectedClient.getId()){
                        sale.setClient(null);
                        ((SalesDomainControllerImpl) this.domainController).getSession().save(sale);
                    }
                }
                ((SalesDomainControllerImpl) this.domainController).getSession().delete(selectedClient);
                tx.commit();
                clientTableModel.populateWithData(domainController.loadAllClients());
                clientTableModel.fireTableDataChanged();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    public void deleteFromStock(StockItem removedItem) {
        if (removedItem != null) {

            try {
                Transaction tx = ((SalesDomainControllerImpl) this.domainController).getSession().beginTransaction();
                for (Sale sale : domainController.loadPurchaseHistory()) {
                    for (SoldItem item : sale.getSoldItems()) {
                        if (item.getStockItem() != null) {
                            if (item.getStockItem().getId() == removedItem.getId()) {
                                item.setStockItem(null);
                                ((SalesDomainControllerImpl) this.domainController).getSession().save(item);
                            }
                        }
                    }
                }
                ((SalesDomainControllerImpl) this.domainController).getSession().delete(removedItem);
                tx.commit();
                warehouseTableModel.populateWithData(domainController.loadWarehouseState());
                warehouseTableModel.fireTableDataChanged();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
}
