package info.bukova.isspst.ui.main.orders.created;

import info.bukova.isspst.data.Address;
import info.bukova.isspst.data.AddressEmb;
import info.bukova.isspst.data.Order;
import info.bukova.isspst.data.OrderItem;
import info.bukova.isspst.services.IsspstException;
import info.bukova.isspst.services.addressbook.AdbService;
import info.bukova.isspst.services.addressbook.AddressFinder;
import info.bukova.isspst.services.orders.OrderService;
import info.bukova.isspst.services.settings.GlobalSettingsService;
import info.bukova.isspst.ui.FormViewModel;
import info.bukova.isspst.validators.OrderFormValidator;

import java.math.BigDecimal;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.zkoss.bind.BindUtils;
import org.zkoss.bind.SimpleForm;
import org.zkoss.bind.annotation.BindingParam;
import org.zkoss.bind.annotation.Command;
import org.zkoss.bind.annotation.GlobalCommand;
import org.zkoss.bind.annotation.Init;
import org.zkoss.bind.annotation.NotifyChange;
import org.zkoss.zk.ui.Executions;
import org.zkoss.zk.ui.select.annotation.WireVariable;
import org.zkoss.zul.Messagebox;
import org.zkoss.zul.Window;
import org.zkoss.zul.impl.InputElement;

public class OrderForm extends FormViewModel<Order>
{
	private final static Logger log = LoggerFactory.getLogger(OrderForm.class.getName());

	@WireVariable
	private AdbService adbService;
	@WireVariable
	private AddressFinder addressFinderAres;
	@WireVariable
	private AddressFinder addressFinderTaxID;
	
	@WireVariable
	protected GlobalSettingsService settingsService;

	@WireVariable
	protected OrderService orderService;

	protected OrderFormValidator orderFormValidator;

	protected OrderItem selectedItem;

	protected Address selectedSuppAddrItem;

	protected Address selectedDeliveryAddrItem;

	protected String suppCompany;

	protected String deliveryCompany;

	protected List<OrderItem> syncOrderItems;

	/**
	 * Obsah záznamu před editací
	 */
	protected Order recordBeforeEdit;

	@Init(superclass = true)
	public void initOrderForm()
	{
		this.orderFormValidator = new OrderFormValidator();

		if (getDataBean().getSuplier() != null)	
		{
			if (getDataBean().getSuplier().getAddress().getId() != 0)
			{
				this.selectedSuppAddrItem = this.getDataBean().getSuplier().getAddress();
			}
			this.suppCompany = getDataBean().getSuplier().getCompany();
		}
		else
		{
			this.getDataBean().setSuplier(new AddressEmb());
		}

		if (this.getDataBean().getDeliveryAddress() == null)
		{
			this.getDataBean().setDeliveryAddress(new AddressEmb());
		}

		this.selectedDeliveryAddrItem = this.getDataBean().getDeliveryAddress().getAddress();
		this.deliveryCompany = this.selectedDeliveryAddrItem.getCompany();

		if (this.getDataBean().getAddress() == null)
		{
			this.getDataBean().setAddress(new AddressEmb());
		}

		this.syncOrderItems = this.getDataBean().getItems();

		try
		{
			this.recordBeforeEdit = (Order) this.getDataBean().clone();
		}
		catch (CloneNotSupportedException e)
		{
			log.error("Nelze provést hlubokou kopii objednávky!");
			e.printStackTrace();
		}
	}

	public OrderFormValidator getOrderFormValidator()
	{
		return orderFormValidator;
	}

	public void setOrderFormValidator(OrderFormValidator orderFormValidator)
	{
		this.orderFormValidator = orderFormValidator;
	}

	public List<Address> getSuppAddresses()
	{
		return adbService.getAll();
	}

	public List<Address> getDeliveryAddresses()
	{
		return settingsService.getSettings().getAllShippingAddrs();
	}

	public Address getInvoiceAddress()
	{
		return settingsService.getSettings().getMainAddress();
	}

	public OrderItem getSelectedItem()
	{
		return this.selectedItem;
	}

	public void setSelectedItem(OrderItem selectedItem)
	{
		this.selectedItem = selectedItem;
	}

	public Address getSelectedSuppAddrItem()
	{
		return selectedSuppAddrItem;
	}

	public void setSelectedSuppAddrItem(Address selectedSuppAddrItem)
	{
		this.selectedSuppAddrItem = selectedSuppAddrItem;
	}

	public Address getSelectedDeliveryAddrItem()
	{
		return selectedDeliveryAddrItem;
	}

	public void setSelectedDeliveryAddrItem(Address selectedDeliveryAddrItem)
	{
		this.selectedDeliveryAddrItem = selectedDeliveryAddrItem;
	}

	public String getSuppCompany()
	{
		return suppCompany;
	}

	public void setSuppCompany(String suppCompany)
	{
		this.suppCompany = suppCompany;
	}

	public String getDeliveryCompany()
	{
		return deliveryCompany;
	}

	public void setDeliveryCompany(String deliveryCompany)
	{
		this.deliveryCompany = deliveryCompany;
	}

	public List<OrderItem> getSyncOrderItems()
	{
		return syncOrderItems;
	}

	public void setSyncOrderItems(List<OrderItem> syncOrderItems)
	{
		this.syncOrderItems = syncOrderItems;
	}

	public Order getRecordBeforeEdit()
	{
		return recordBeforeEdit;
	}

	public void setRecordBeforeEdit(Order recordBeforeEdit)
	{
		this.recordBeforeEdit = recordBeforeEdit;
	}

	@Command
	@NotifyChange("dataBean")
	public void doFillSuppAddress()
	{
		this.getDataForm().bind();
		AddressEmb addr;

		if (this.selectedSuppAddrItem == null)
		{
			addr = this.getDataBean().getSuplier();
			addr.setId(0);
			addr.setCompany(this.suppCompany);
		}
		else
		{
			// Naplnit pole podle vybrané adresy z comba
			addr = new AddressEmb(this.selectedSuppAddrItem);
		}

		this.getDataBean().setSuplier(addr);
	}

	@Command
	@NotifyChange("dataBean")
	public void doFillDeliveryAddress()
	{
		this.getDataForm().bind();
		AddressEmb addr;

		if (this.selectedDeliveryAddrItem == null)
		{
			addr = this.getDataBean().getDeliveryAddress();
			addr.setId(0);
			addr.setCompany(this.deliveryCompany);
		}
		else
		{
			// Naplnit pole podle vybrané adresy z comba
			addr = new AddressEmb(this.selectedDeliveryAddrItem);
		}

		this.getDataBean().setDeliveryAddress(addr);
	}

	@Command
	public void onFocusItem(@BindingParam("item") OrderItem item, @BindingParam("ctrl") InputElement ctrl)
	{
		// this.selItemIndex = this.getDataBean().getItems().indexOf(item);
		this.selectedItem = item;

		if (ctrl != null)
		{
			ctrl.select();
		}
	}

	protected void calcAndUpdateFormTotalPrice(SimpleForm form)
	{
		if (form != null)
		{
			BigDecimal sumTotal = orderService.calcSumTotalFromItems(this.getDataBean().getItems());
			form.setField("total", sumTotal);
			BindUtils.postNotifyChange(null, null, form, "*");
		}
	}

	@Command
	@NotifyChange({ "selectedItem", "syncOrderItems" })
	public void recalculate(@BindingParam("form") SimpleForm form, @BindingParam("changed") String source)
	{
		if (this.selectedItem == null)
		{
			log.warn("Zavolat z formuláře onFocus pro nastavení vybrané položky!");
			return;
		}

		// Recalculate selected item
		if ((source != null) && (source.equals("total")))
		{
			this.selectedItem = orderService.calcItemValuesFromItemTotal(this.selectedItem);
		}
		else
		{
			this.selectedItem = orderService.calcTotalInItem(this.selectedItem);
		}

		// Calculate total price at form
		this.calcAndUpdateFormTotalPrice(form);
	}

	@Override
	protected void doAdd()
	{
		// Zjisti, zda se změnil příznak objednávky (objednáno/neobjednáno)
		boolean orderedChanged = (this.recordBeforeEdit.isOrdered() != this.getDataBean().isOrdered());
		// Aktualizovat příznak schválených položek, aby se nemohli vložit do
		// jiných objednávek
		orderService.addApprovedItems(this.getDataBean(), orderedChanged);
		BindUtils.postGlobalCommand(null, null, "reload", null);
	}

	@Override
	protected void doSave()
	{
		// Zjisti, zda se změnil příznak objednávky (objednáno/neobjednáno)
		boolean orderedChanged = (this.recordBeforeEdit.isOrdered() != this.getDataBean().isOrdered());
		// Aktualizovat příznak schválených položek, aby se nemohli vložit do
		// jiných objednávek
		orderService.updateApprovedItems(this.getDataBean(), orderedChanged);
	}
	
	@Command
	@NotifyChange({"dataBean", "suppCompany"})
	public void searchAddress() 
	{
		getDataForm().bind();
		
		Address adr = getDataBean().getSuplier().getAddress();
		
		if (adr.getIc() != 0)
		{
			try 
			{
				adbService.fillFoundData(addressFinderTaxID, adr);
				getDataBean().setSuplier(new AddressEmb(adr));
				suppCompany = adr.getCompany();
			}
			catch (IsspstException e)
			{
				Messagebox.show("Chyba při hledání adresy", "Chyba", Messagebox.OK, Messagebox.ERROR);
				return;
			}
			
		}
		else 
		{
			Map<String, List<Address>> arg = new HashMap<String, List<Address>>();
			try {
				arg.put("result", adbService.lookForAddr(addressFinderAres, adr));
			} catch (IsspstException e) {
				Messagebox.show("Chyba při hledání adresy", "Chyba", Messagebox.OK, Messagebox.ERROR);
				return;
			}
			
			Window resWin = (Window) Executions.createComponents("/lists/addressbook/addrFindResult.zul", null, arg);
			resWin.doModal();
		}
	}
	
	@GlobalCommand
	@NotifyChange({"dataBean", "suppCompany"})
	public void selectAddress(@BindingParam("selected") Address selected, @BindingParam("window") Window window) {
		try {
			adbService.fillFoundData(addressFinderTaxID, selected);
		} catch (IsspstException e) {
			e.printStackTrace();
		}
		
		Address adr = getDataBean().getSuplier().getAddress();
		adbService.mergeAddress(adr, selected, true);
		getDataBean().setSuplier(new AddressEmb(adr));
		suppCompany = adr.getCompany();
		
		if (window != null)
			window.detach();
	}
}
