package info.bukova.isspst.ui;

import info.bukova.isspst.StringUtils;
import info.bukova.isspst.data.DataModel;
import info.bukova.isspst.services.IsspstException;
import info.bukova.isspst.services.Service;
import info.bukova.isspst.services.ValidationException;
import org.hibernate.exception.ConstraintViolationException;
import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.security.access.AccessDeniedException;
import org.zkoss.bind.annotation.BindingParam;
import org.zkoss.bind.annotation.Command;
import org.zkoss.bind.annotation.ExecutionArgParam;
import org.zkoss.bind.annotation.Init;
import org.zkoss.bind.annotation.NotifyChange;
import org.zkoss.zul.Messagebox;
import org.zkoss.zul.Window;

import java.sql.SQLException;
import java.util.Map;

public class FormViewModel<T extends DataModel> extends BindingViewModel<T>
{
	private T dataBean;
	private Map<String, String> errMessages;
	private Service<T> service;
	protected boolean newRec;
	private ServiceConstraint<T> constraint;

	@Init
	public void initFormViewModel(@ExecutionArgParam("selected") T selected, @ExecutionArgParam("service") Service<T> service)
	{
		super.initBindingViewModel();

		this.dataBean = selected;
		this.service = service;
		constraint = new ServiceConstraint<T>();
		constraint.setDataBean(selected);
		constraint.setService(service);

		this.getDataForm().setDataBean(selected);
		
		if (selected.getId() == 0 && selected.getCreated() == null)
		{
			newRec = true;
		}
		else
		{
			newRec = false;
		}
	}

	public ServiceConstraint<T> getConstriant()
	{
		return constraint;
	}

	public T getDataBean()
	{
		return dataBean;
	}

	public boolean isNewRec()
	{
		return this.newRec;
	}

	public boolean isEditRec()
	{
		return !this.newRec;
	}

	@Command
	@NotifyChange("errMessages")
	public void save(@BindingParam("window") Window win)
	{
		try
		{
			if (newRec)
			{
				doAdd();
			}
			else
			{
				doSave();
			}
			win.detach();
		}
		catch (ValidationException e)
		{
			errMessages = e.getMessages();
			String classErr = errMessages.get("CLASS_ERR");

			if (classErr == null)
			{
				classErr = "";
			}

			Messagebox.show(StringUtils.localize("DbValidationError"), StringUtils.localize("Error"), Messagebox.OK, Messagebox.ERROR);
		}
		catch (IsspstException e)
		{
			if (e.getReason() != null)
			{
				Messagebox.show(StringUtils.localize(e.getReason()), StringUtils.localize("Error"), Messagebox.OK, Messagebox.ERROR);
			}
			else
			{
				Messagebox.show(StringUtils.localize("DbSaveError"), StringUtils.localize("Error"), Messagebox.OK, Messagebox.ERROR);
			}
			dataBean.setValid(false);
		}
		catch (AccessDeniedException e)
		{
			Messagebox.show(StringUtils.localize("ErrorRights"), StringUtils.localize("Error"), Messagebox.OK, Messagebox.ERROR);
		}
		catch (ConstraintViolationException e)
		{
			Messagebox.show(StringUtils.localizeDbErr(e.getSQLException().getMessage()), StringUtils.localize("Error"), Messagebox.OK, Messagebox.ERROR);
			dataBean.setValid(false);
		}
		catch (DataIntegrityViolationException e)
		{
			Throwable actualException = e;
			Throwable previousException = actualException.getCause();
			String msg = actualException.getLocalizedMessage();
			boolean printStackTree = true;

			if (previousException != null)
			{
				if (previousException instanceof ConstraintViolationException)
				{
					ConstraintViolationException cve = (ConstraintViolationException) previousException;
					SQLException sqle = cve.getSQLException();
					int errCode = sqle.getErrorCode();

					if (errCode == 1062)
					{
						printStackTree = false;
						msg = sqle.getMessage();
						msg = StringUtils.localizeDbErr(msg);
					}
				}
			}

			if (printStackTree)
			{
				e.printStackTrace();
			}

			Messagebox.show(StringUtils.localize("DbSaveError") + "\n\n" + msg, StringUtils.localize("Error"), Messagebox.OK, Messagebox.ERROR);
			dataBean.setValid(false);
		}
		catch (Exception e)
		{
			e.printStackTrace();
			Messagebox.show(StringUtils.localize("DbSaveError"), StringUtils.localize("Error"), Messagebox.OK, Messagebox.ERROR);
			dataBean.setValid(false);
		}
	}

	public Map<String, String> getErrMessages()
	{
		return errMessages;
	}

	protected void setErrMesages(Map<String, String> msgs)
	{
		this.errMessages = msgs;
	}

	protected void doSave()
	{
		service.update(dataBean);
	}

	protected void doAdd()
	{
		service.add(dataBean);
	}

	public boolean isCanSave()
	{
		return true;
	}
}
