package un.broker.asysad.client.rules;

import static so.kernel.core.KernelEventConstants.DOCUMENT_VERIFY;
import static un.broker.asysad.C_asysad.*;
import java.math.BigDecimal;
import java.text.MessageFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map.Entry;
import java.util.regex.Pattern;
import so.kernel.client.DesktopMain;
import so.kernel.client.VisualForm;
import so.kernel.core.DataSet;
import so.kernel.core.KNumberedSubDataSet;
import so.kernel.core.KNumberedSubDocument;
import so.kernel.core.KernelEvent;
import so.kernel.core.Rule;
import so.kernel.core.interfaces.DocumentInterface;
import so.kernel.core.interfaces.KNumberedDocumentInterface;
import so.swing.KOptionPane;
import un.adtcommons.client.visual.DHMMapManager;
import un.asyref.UNVEHTAR.C_UNVEHTAR;
import un.broker.asysad.D_asysad;
import un.broker.asysad.client.VD_asysad;
import un.broker.asysad.client.VF_Vehicle;
import un.globalConfig.util.GlobalConfigUtilities;
import un.kernel.core.HistorizedModelDelegator;
/** <PATCH ID="Vehicle information page" VERSION="4.2.2" TYPE="JM" DATE="Jun 16, 2015" AUTHOR="Leonardo Flores"> **/
public class R_ManageViewVehicleForm extends Rule {

	private D_asysad doc;
	private VD_asysad vd;
	private HashSet<String> included;
	private HashSet<String> excluded;
	private static Pattern WHITESPACE = Pattern.compile("\\s");

	public R_ManageViewVehicleForm(D_asysad doc, VD_asysad vd) {
		super();
		this.doc = doc;
		this.vd = vd;
	}

	protected void apply(KernelEvent e) {
		boolean isVisible = false;
		
		// 1. Iterate over all items
		KNumberedSubDataSet items = ((KNumberedSubDataSet)this.doc.ds(ITM));
		int totalItems = items.countDocuments();
		HashMap<Integer,Integer> supVsVeh = new HashMap<Integer,Integer>();
		for (int i = 1; i <= totalItems; i++){
			KNumberedSubDocument item = items.getDocument(i);
			String tarifCode = item.ds(TAR).ds(HSC).de(NB1).getString("").trim() + item.ds(TAR).ds(HSC).de(NB2).getString("").trim() + item.ds(TAR).ds(HSC).de(NB3).getString("").trim();
			if (isVisibleCode(tarifCode)){
				isVisible = true;
				if (e.getID() == DOCUMENT_VERIFY.getID()) { // In case of document verify, check that exist an entry on vehicle page
					int itemNumber = item.ds(KNumberedDocumentInterface.KEYS_ID).de(KNumberedSubDocument.RNK).getInt(0);

					if (!hasEntry(itemNumber)) {
						String message = MessageFormat.format(lng("Vehicle information is needed for item {0}. Please, add an entry"),itemNumber);
						setError(item.ds(KNumberedDocumentInterface.KEYS_ID).de(KNumberedSubDocument.RNK),message,e);
					} else {
						// Get how many vehicles are needed (from supplementary units)
						KNumberedSubDataSet sups = (KNumberedSubDataSet)item.ds(TAR).ds(SUP);
						KNumberedSubDocument sup = sups.countDocuments() > 0 ? sups.getDocument(1) : null;
						
						// Assumption. if supplementary unit are required for the commodity code, then, it represents how many vehicles contain the declaration item (no fractional amount)
						BigDecimal qty = GlobalConfigUtilities.getBigDecimal(sup.de(QTY),"SUP",BigDecimal.ZERO);
						if (qty.compareTo(BigDecimal.ZERO) > 0) supVsVeh.put(itemNumber,qty.setScale(0,BigDecimal.ROUND_UP).intValue());

					}
				}else {
					break;
				}
			}
		}
		KNumberedSubDataSet vehicles = ((KNumberedSubDataSet)this.doc.ds(VEH));
		int totalVehicles = vehicles.countDocuments();
		doc.setVisibleOperationEvent(R_PRINTOUT_VEHICLE,isVisible);
		if (isVisible && e.getID() == DOCUMENT_VERIFY.getID()) {
			for (int i = 1; i <= totalVehicles; i++){
				KNumberedSubDocument vehicle = vehicles.getDocument(i);
				String vinNumber = vehicle.ds(DocumentInterface.NORMAL_ID).de(CHA).getString("").trim();
				int itemNumber = vehicle.ds(DocumentInterface.NORMAL_ID).de(ITM).getInt(0);
				if (WHITESPACE.matcher(vinNumber).find()) {
					String message = lng("Spaces are not allowed on chassis number [{0}] - Please, correct vehicle entry on line {1}");
					message = MessageFormat.format(message,vinNumber,vehicle.ds(DocumentInterface.KEYS_ID).de(KNumberedSubDocument.RNK).getInt(0));
					KOptionPane.showMessageDialog(DesktopMain.sharedInstance(),message,lng("Error"),KOptionPane.ERROR_MESSAGE);
					e.consume();
				}
				if (!supVsVeh.containsKey(itemNumber)) {
					String message = lng("Item {0} is not a vehicle tariff and is linked with vehicle chassis {1}, please, update your vehicle information");
					message = MessageFormat.format(message,itemNumber,vinNumber);
					KOptionPane.showMessageDialog(DesktopMain.sharedInstance(),message,lng("Error"),KOptionPane.ERROR_MESSAGE);
					e.consume();
				} else supVsVeh.put(itemNumber,supVsVeh.get(itemNumber) - 1);
			}

			// Verify amount of vehicles vs supplementary units
			for (Entry<Integer,Integer> entry : supVsVeh.entrySet()) {
				if (entry.getValue() != 0) {
					DataSet item = items.getDocument(entry.getKey());
					DataSet sup = ((KNumberedSubDataSet)item.ds(TAR).ds(SUP)).getDocument(1);
					int qty = GlobalConfigUtilities.getBigDecimal(sup.de(QTY),"SUP",BigDecimal.ZERO).setScale(0,BigDecimal.ROUND_UP).intValue();
					int qtyVeh = qty - entry.getValue();
					String message = lng("Item {0} has {1} supplementary units and {2} vehicle entries, please, update quantities accordingly");
					message = MessageFormat.format(message,String.valueOf(entry.getKey()),String.valueOf(qty),String.valueOf(qtyVeh));
					KOptionPane.showMessageDialog(DesktopMain.sharedInstance(),message,lng("Error"),KOptionPane.ERROR_MESSAGE);
					e.consume();
				}
			}
		} else if (!isVisible && e.getID() == DOCUMENT_VERIFY.getID()) {
			for (int i = totalVehicles; i > 0; i--) vehicles.deleteDocument(i);
		}

		// 2. Set visibility
		int formCount = this.vd.getVisualFormCount();
		for (int i = 0; i < formCount; i++){
			VisualForm form = this.vd.getVisualFormAt(i);
			if (VF_Vehicle.class.isInstance(form)){
				if (isVisible != this.vd.isFormVisible(form.getName())) {
					this.vd.setFormVisible(form, isVisible);
				}
				break;
			}
		}
	}

	private boolean hasEntry(int itemNumber) {
		KNumberedSubDataSet vehicles = ((KNumberedSubDataSet)this.doc.ds(VEH));
		int totalVehicles = vehicles.countDocuments();
		for (int i = 1; i <= totalVehicles; i++){
			KNumberedSubDocument vehicle = vehicles.getDocument(i);
			if (vehicle.de(ITM).getInt(0) == itemNumber) return true;
		}
		return false;
	}

	private boolean isVisibleCode(String tarifCode) {
		if (included == null || excluded == null) initTariffList();
		Iterator<String> it = included.iterator();
		while (it.hasNext()){
			String visibleCode = it.next();
			if (tarifCode.startsWith(visibleCode) && !isTariffException(tarifCode)) return true;
		}
		return false;
	}

	private boolean isTariffException(String tarifCode) {
		Iterator<String> it = excluded.iterator();
		while (it.hasNext()) {
			String tariffEx = it.next();
			if (tarifCode.startsWith(tariffEx)) return true;
		}
		return false;
	}

	private void initTariffList() {
		included = new HashSet<String>();
		excluded = new HashSet<String>();
		Date wde = (Date)doc.ds(PTY).de(WDE).getContent();
		if (wde != null) {
			HistorizedModelDelegator model = DHMMapManager.getModel(doc,"UN_VEH_TAR");
			int rowCount = model.getRowCount();
			for (int i = 0; i < rowCount; i++) {
				Object type = model.getValueAt(i,C_UNVEHTAR.TAR_TYP);
				String tariff = (String)model.getValueAt(i,C_UNVEHTAR.TAR_COD);
				if (type != null && tariff != null && !"".equals(tariff.trim())) {
					if (C_UNVEHTAR.TYP_INCLUDE.equals(type)) included.add(tariff.trim());
					else if (C_UNVEHTAR.TYP_EXCLUDE.equals(type)) excluded.add(tariff.trim());
				}
			}
		}
	}

	private static String lng(String property) {
		return so.i18n.IntlObj.createMessage("un.asybrk", property);
	}
}
