package info.bukova.isspst.ui.workgroups;

import info.bukova.isspst.Constants;
import info.bukova.isspst.StringUtils;
import info.bukova.isspst.data.JobMapping;
import info.bukova.isspst.data.Member;
import info.bukova.isspst.data.Role;
import info.bukova.isspst.data.User;
import info.bukova.isspst.data.Workgroup;
import info.bukova.isspst.services.users.RoleService;
import info.bukova.isspst.services.users.UserService;
import info.bukova.isspst.services.workgroups.WorkgroupException;
import info.bukova.isspst.services.workgroups.WorkgroupService;
import info.bukova.isspst.ui.BigDecimalConverter;
import info.bukova.isspst.ui.FormViewModel;
import info.bukova.isspst.ui.renderers.JobMappingItemRenderer;
import info.bukova.isspst.ui.renderers.UserItemRenderer;
import org.zkoss.bind.annotation.BindingParam;
import org.zkoss.bind.annotation.Command;
import org.zkoss.bind.annotation.Init;
import org.zkoss.bind.annotation.NotifyChange;
import org.zkoss.zk.ui.event.DropEvent;
import org.zkoss.zk.ui.select.annotation.WireVariable;
import org.zkoss.zul.Listitem;
import org.zkoss.zul.Messagebox;

import java.util.ArrayList;
import java.util.List;
import java.util.Set;

import static ch.lambdaj.Lambda.filter;
import static ch.lambdaj.Lambda.having;
import static ch.lambdaj.Lambda.on;
import static org.hamcrest.Matchers.startsWith;

public class WorkgroupForm extends FormViewModel<Workgroup> {
	
	@WireVariable
	private UserService userService;
	@WireVariable
	private RoleService roleService;
	@WireVariable
	private WorkgroupService workgroupService;
	private List<Member> users;
	private String findUser;
	private List<Member> selectedUsers;
	private BigDecimalConverter bdConverter;
	private JobMappingItemRenderer itemRenderer;
	private UserItemRenderer userItemRenderer;

	@Init(superclass = true)
	public void init() {
		users = new ArrayList<Member>();
		users.addAll(userService.getAll());
		selectedUsers = new ArrayList<Member>();
		bdConverter = new BigDecimalConverter();
		itemRenderer = new JobMappingItemRenderer();
		userItemRenderer = new UserItemRenderer();
	}
	
	public List<Member> getUsers() {
		if (getDataBean().isCentre()) {
			List<Member> listWithWg = new ArrayList<Member>(users);
			
			List<Workgroup> wg = workgroupService.getWorkgroups();
			
			for (Workgroup w : wg) {
				if (!workgroupService.isMember(getDataBean(), w)) {
					listWithWg.add(w);
				}
			}
			
			return listWithWg;
		}
		
		return users;
	}
	
	public List<Role> getWorkgroupRoles() {
		if (getDataBean().isCentre()) {
			return roleService.getCentreRoles();
		} else {
			return roleService.getWorkgroupRoles();
		}
	}
	
	@NotifyChange({"workgroupRoles", "centre", "users"})
	public void setCentre(boolean centre) {
		getDataBean().setCentre(centre);
		getDataBean().getMembers().clear();
		
		if (centre) {
			List<Role> centreRoles = roleService.getCentreRoles();
			for (Role r : centreRoles) {
				if (!r.getAuthority().equals(Constants.ROLE_USER)) {
					List<User> users = userService.getUsersWithRole(r);
					for (User u : users) {
						workgroupService.loadParents(u);
						workgroupService.addMember(getDataBean(), u, r);
					}
				}
			}
			
			getDataBean().setLimit(null);
		}
	}
	
	public boolean getCentre() {
		return getDataBean().isCentre();
	}
	
	@Command
	@NotifyChange({"users", "dataBean"})
	public void addMember(@BindingParam("event") DropEvent event) {
		 Set<Listitem> selected = ((Listitem)event.getDragged()).getListbox().getSelectedItems();
		 
		 if (selected.isEmpty()) {
			 try {
				 Member u = ((Listitem)event.getDragged()).getValue();
				 moveUser(u, event);
			 } catch(ClassCastException e) {
				 JobMapping u = ((Listitem)event.getDragged()).getValue();
				 moveUser(u, event);
			 }
			 
			 
			 return;
		 }
		 
		 for (Listitem li : selected) {
			 try {
				 Member u = li.getValue();
				 moveUser(u, event);
			 } catch (ClassCastException e) {
				 JobMapping u = li.getValue();
				 moveUser(u, event);
			 }
		 }
	}
	
	private void moveUser(JobMapping u, DropEvent event) {
		String source = getSource(event);
		String target = getTarget(event);
		
		if (source.equals(target)) {
			return;
		}
		
		workgroupService.loadMembers(getDataBean());
		workgroupService.loadParents(u.getMember());
		workgroupService.removeMember(getDataBean(), u);
		
		if (!target.equals("users")) {
			moveUser(u.getMember(), event);
		}
	}

	private void moveUser(Member u, DropEvent event) {
		String source = getSource(event);
		String target = getTarget(event);
		
		if (source.equals(target)) {
			return;
		}
		
		workgroupService.loadMembers(getDataBean());
		workgroupService.loadParents(u);
		
		if (!u.isPerson()) {
			workgroupService.loadMembers((Workgroup) u);
		} else if (!getDataBean().isCentre()) {
			workgroupService.loadParentsMembers(getDataBean());
		}
		
		try {
			workgroupService.addMember(getDataBean(), u, roleService.getRoleByAuthority(target));
			
			if (!u.isPerson()) {
				users.remove(u);
			}
		} catch (WorkgroupException e) {
			String message;
			String title;
			
			if (!getDataBean().isCentre()) {
				message = StringUtils.localize("WorkgroupFormUserIsCenterMember");
				title = StringUtils.localize("WorkgroupFormCannotAddUser");
			} else {
				message = StringUtils.localize("WorkgroupFormMemberIsCenterMember");
				title = StringUtils.localize("WorkgroupFormCannotAddWorkgroup");
			}
			
			Messagebox.show(message, title, Messagebox.OK, Messagebox.ERROR);
		}
		
	}
	
	private String getSource(DropEvent event) {
		return ((Listitem)event.getDragged()).getListbox().getId();
	}
	
	private String getTarget(DropEvent event) {
		String target;
		
		if (event.getTarget() instanceof Listitem) {
			target = ((Listitem)event.getTarget()).getListbox().getId();
		} else {
			target = event.getTarget().getId();
		}
		
		return target;
	}

	public String getFindUser() {
		return findUser;
	}

	public void setFindUser(String findUser) {
		this.findUser = findUser;
	}

	public List<Member> getSelectedUsers() {
		return selectedUsers;
	}

	public void setSelectedUsers(List<Member> selectedUser) {
		this.selectedUsers = selectedUser;
	}
	
	@Command
	@NotifyChange("selectedUsers")
	public void find() {
		List<Member> found = filter(having(on(Member.class).getFullName(), startsWith(findUser)), users);
		
		if (!found.isEmpty()) {
			if (selectedUsers == null) {
				selectedUsers = new ArrayList<Member>();
			} else {
				selectedUsers.clear();
				selectedUsers.add(found.get(0));
			}
		}
	}

	public BigDecimalConverter getBdConverter() {
		return bdConverter;
	}

	public JobMappingItemRenderer getItemRenderer() {
		return itemRenderer;
	}

	public UserItemRenderer getUserItemRenderer() {
		return userItemRenderer;
	}
}
