package info.bukova.isspst.ui.settings;

import info.bukova.isspst.Constants;
import info.bukova.isspst.StringUtils;
import info.bukova.isspst.data.Address;
import info.bukova.isspst.data.Requirement;
import info.bukova.isspst.data.SettingsData;
import info.bukova.isspst.data.Vehicle;
import info.bukova.isspst.services.settings.GlobalSettingsService;
import info.bukova.isspst.sort.ReflectionTools;
import info.bukova.isspst.storage.FileStorage;
import info.bukova.isspst.ui.BindingViewModel;
import info.bukova.isspst.ui.LocaleConverter;
import info.bukova.isspst.ui.SecurityHelper;
import info.bukova.isspst.validators.GlobalSettingValidator;

import java.awt.image.RenderedImage;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Set;

import javax.imageio.ImageIO;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.zkoss.bind.SimpleForm;
import org.zkoss.bind.Validator;
import org.zkoss.bind.annotation.BindingParam;
import org.zkoss.bind.annotation.Command;
import org.zkoss.bind.annotation.ContextParam;
import org.zkoss.bind.annotation.ContextType;
import org.zkoss.bind.annotation.Init;
import org.zkoss.bind.annotation.NotifyChange;
import org.zkoss.zk.ui.event.UploadEvent;
import org.zkoss.zk.ui.select.annotation.WireVariable;
import org.zkoss.zul.Window;

public class GlobalSettingsVM extends BindingViewModel<SettingsData>
{
	private final static Logger log = LoggerFactory.getLogger(GlobalSettingsVM.class.getName());

	@WireVariable
	private GlobalSettingsService settingsService;
	private SettingsData settings;
	private LocaleConverter locConverter;
	private Address selAddress;
	private List<Integer> refundsHours;
	@WireVariable
	private FileStorage storage;

	private Validator globalSettingValidator;
		
	@Init(superclass = true)
	public void init(@BindingParam("window") Window mainWindow) {
		settings = settingsService.getSettings();
		locConverter = new LocaleConverter();
		setRefundsHours(settings.getRefunds().keySet());

		this.getDataForm().setDataBean(this.settings);
		this.globalSettingValidator = new GlobalSettingValidator(mainWindow);
	}

	public SettingsData getSettings() {
		return settings;
	}
	
	@Command
	public void save(@BindingParam("window") Window window) {
		settingsService.updateSettings();
		window.detach();
	}
	
	@Command
	@NotifyChange({"settings", "stampImg"})
	public void uploadStamp(@ContextParam(ContextType.TRIGGER_EVENT) UploadEvent upEvent) {
		int i = upEvent.getMedia().getName().lastIndexOf(".");
		String fileName = "StampImageFile" + upEvent.getMedia().getName().substring(i);

		storage.saveFile(upEvent.getMedia().getByteData(), fileName);
		settings.setStampFile(fileName);
	}
	
	@Command
	@NotifyChange("stampImg")
	public void removeStamp() {
		storage.removeFile(settings.getStampFile());
		settings.setStampFile(null);
	}

	@Command
	@NotifyChange({ "settings", "logoImg" })
	public void uploadLogo(@ContextParam(ContextType.TRIGGER_EVENT) UploadEvent upEvent) {
		int i = upEvent.getMedia().getName().lastIndexOf(".");
		String fileName = "LogoImageFile" + upEvent.getMedia().getName().substring(i);
		storage.saveFile(upEvent.getMedia().getByteData(), fileName);
		settings.setLogoFile(fileName);
	}

	@Command
	@NotifyChange("logoImg")
	public void removeLogo()
	{
		storage.removeFile(settings.getLogoFile());
		settings.setLogoFile(null);
	}

	public List<String> getRequirementFields() {
		return ReflectionTools.getEntityFields(Requirement.class);
	}
	
	public boolean isCanSave() {
		return SecurityHelper.isAllGranted(Constants.ROLE_ADMIN);
	}

	public LocaleConverter getLocConverter() {
		return locConverter;
	}
	
	private void insertString(SimpleForm form, String property, String field) {
		if (form == null) {
			log.warn("SimpleForm neexistuje !!!");
			return;
		}

		Set<String> set = form.getFieldNames();

		if (set.contains(property)) {
			String text = (String) form.getField(property);
			text += "[" + field + "]";
			form.setField(property, text);
			this.getDataForm().bind();
			return;
		}

		log.warn("SimpleForm property '" + property + "' neexistuje !!!");
	}

	@Command
	@NotifyChange("settings")
	public void insertField2Fx(@BindingParam("form") SimpleForm form, @BindingParam("property") String property, @BindingParam("field") String field) {
		this.insertString(form, property, field);
	}
	
	@Command
	@NotifyChange("settings")
	public void insertUrl2Fx(@BindingParam("form") SimpleForm form, @BindingParam("property") String property) {
		this.insertString(form, property, Constants.MAIL_URL_KEYWORD);
	}

	@Command
	@NotifyChange("settings")
	public void addAddress() {
		settings.getShippingAddrs().add(new Address());
	}
	
	@Command
	@NotifyChange("settings")
	public void removeAddress(@BindingParam("addr") Address addr) {
		settings.getShippingAddrs().remove(addr);
	}
	
	@Command
	@NotifyChange("settings")
	public void addVehicle() {
		settings.getVehicles().add(new Vehicle());
	}
	
	@Command
	@NotifyChange("settings")
	public void removeVehicle(@BindingParam("vehicle") Vehicle vehicle) {
		settings.getVehicles().remove(vehicle);
	}

	public Address getSelAddress() {
		return selAddress;
	}

	public void setSelAddress(Address selAddress) {
		this.selAddress = selAddress;
	}

	public List<Integer> getRefundsHours() {
		return refundsHours;
	}

	private void setRefundsHours(Set<Integer> refundsHours) {
		this.refundsHours = new ArrayList<Integer>(settings.getRefunds().keySet()); 
		Collections.sort(this.refundsHours);
	}
	
	public RenderedImage getStampImg() {
		if (StringUtils.isNullOrEmpty(settings.getStampFile())) {
			return null;
		}
		
		try {
			return ImageIO.read(storage.file(settings.getStampFile()));
		} catch (IOException e) {
			return null;
		}
	}

	public RenderedImage getLogoImg() {
		if (StringUtils.isNullOrEmpty(settings.getLogoFile())) {
			return null;
		}

		try {
			return ImageIO.read(storage.file(settings.getLogoFile()));
		}
		catch (IOException e) {
			return null;
		}
	}

	public Validator getGlobalSettingValidator() {
		return globalSettingValidator;
	}

	public void setGlobalSettingValidator(Validator globalSettingValidator) {
		this.globalSettingValidator = globalSettingValidator;
	}
}
