package tvark.beans;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FilenameFilter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import tvark.jsf.JsfUtils;
import tvark.model.Lesson;
import tvark.model.ScheduleModel;
import tvark.old.Property;
import tvark.old.Schedule;

public class ResultsBean {
	
	private static final String SER_KEY_INITIAL = "initial_model";
	
	private static final String SER_KEY_FINAL = "final_model";
	
	private static final String REQ_KEY_INITIAL = "initial_model";
	
	private static final String REQ_KEY_FINAL = "final_model";
	
	private static final Log sLog = LogFactory.getLog(ResultsBean.class);
	
	public static enum DisplayMode {
		Initial,
		Final,
		Both;	
		
		public DisplayMode getInitial() {
			return Initial;
		}
		
		public DisplayMode getFinal() {
			return Final;
		}
		
		public DisplayMode getBoth() {
			return Both;
		}
		
		public boolean isIsInitial() {
			return equals(Initial);
		}
		
		public boolean isIsFinal() {
			return equals(Final);
		}
		
		public boolean isIsBoth() {
			return equals(Both);
		}
		
	}
	
	public static enum ScheduleOwner {
		School,
		Room,
		Teacher,
		Student,
		Group;
		
		public ScheduleOwner getSchool() {
			return School;
		}
		
		public ScheduleOwner getRoom() {
			return Room;
		}
		
		public ScheduleOwner getTeacher() {
			return Teacher;
		}
		
		public ScheduleOwner getStudent() {
			return Student;
		}
		
		public ScheduleOwner getGroup() {
			return Group;
		}
		
		public boolean isIsSchool() {
			return equals(School);
		}
		
		public boolean isIsRoom() {
			return equals(Room);
		}
		
		public boolean isIsTeacher() {
			return equals(Teacher);
		}
		public boolean isIsStudent() {
			return equals(Student);
		}
		public boolean isIsGroup() {
			return equals(Group);
		}
		
	}
	
	private DisplayMode mDisplayMode = DisplayMode.Final;
	private ScheduleOwner mScheduleOwner = ScheduleOwner.School;
	
	private String mStudentId;
	private String mTeacherId;
	private String mGroupId;
	private String mRoomId;
	
	public List<Lesson>[][] getInitialSchedule() {
		return getSchedule(getInitial());
	}
	
	public List<Lesson>[][] getFinalSchedule() {
		return getSchedule(getFinal());
	}
	
	private List<Lesson>[][] getSchedule(ScheduleModel pModel) {
		List<Lesson>[][] result;
		if (mScheduleOwner == null) {
			throw new IllegalStateException();
		} else if (mScheduleOwner.isIsSchool()) {
			result = pModel.getSchedule();			
		} else if (mScheduleOwner.isIsStudent()) {
			result = pModel.getStudentSchedule(mStudentId);
		} else if (mScheduleOwner.isIsTeacher()) {
			result = pModel.getTeacherSchedule(mTeacherId);
		} else if (mScheduleOwner.isIsRoom()) {
			result = pModel.getRoomSchedule(mRoomId);
		} else if (mScheduleOwner.isIsGroup()) {
			result = pModel.getGroupSchedule(mGroupId);
		} else {
			throw new IllegalStateException();
		}
		return result;
	}
	
	public ScheduleModel getInitial() {
		if (JsfUtils.containsRequestAttribute(REQ_KEY_INITIAL)) {
			return (ScheduleModel) JsfUtils.getRequestAttribute(REQ_KEY_INITIAL);
		} else {
			ScheduleModel model = (ScheduleModel) JsfUtils.loadFromSession(SER_KEY_INITIAL);
			JsfUtils.setRequestAttribute(model, REQ_KEY_INITIAL);
			return model;				
		}
	}
		
	public ScheduleModel getFinal() {
		if (JsfUtils.containsRequestAttribute(REQ_KEY_FINAL)) {
			return (ScheduleModel) JsfUtils.getRequestAttribute(REQ_KEY_FINAL);
		} else {
			ScheduleModel model = (ScheduleModel) JsfUtils.loadFromSession(SER_KEY_FINAL);
			JsfUtils.setRequestAttribute(model, REQ_KEY_FINAL);
			return model;				
		}
	}		
	
	public void setSchedules(Schedule pInitial, Schedule pFinal, Property pProperty) {
		ScheduleModel initialModel = new ScheduleModel(pInitial, pProperty);
		ScheduleModel finalModel = new ScheduleModel(pFinal, pProperty);
		JsfUtils.setRequestAttribute(initialModel, REQ_KEY_INITIAL);
		JsfUtils.setRequestAttribute(finalModel, REQ_KEY_FINAL);
		JsfUtils.persistInSession(initialModel, SER_KEY_INITIAL);
		JsfUtils.persistInSession(finalModel, SER_KEY_FINAL);
	}
	
	public byte[] getAsZip() throws IOException {
		
		if (getInitial() == null) {
			return new byte[0];
		}
		ByteArrayOutputStream bos = new ByteArrayOutputStream();
		ZipOutputStream jos = new ZipOutputStream(bos);

		File baseDir = new File(
				getInitial().getOriginalSchedule().getRootDir() + "/" +				
				getInitial().getOriginalSchedule().getFolder());
		File[] dirs = {
				baseDir,
				new File(baseDir.getAbsolutePath() + "/students_initial"),
				new File(baseDir.getAbsolutePath() + "/teachers_initial"),
				new File(baseDir.getAbsolutePath() + "/rooms_initial"),
				new File(baseDir.getAbsolutePath() + "/rooms_optimized"),
				new File(baseDir.getAbsolutePath() + "/students_optimized"),
				new File(baseDir.getAbsolutePath() + "/teachers_optimized")				
		};
		
		List<File> files = new ArrayList<File>();
		for (File dir : dirs) {
			File[] array = dir.listFiles(new FilenameFilter() {

				public boolean accept(File pDir, String pName) {
					return pName.toUpperCase().endsWith(".XML");
				}
			});
			if (array == null) {
				continue;
			}
			files.addAll(Arrays.asList(array));			
		}
		
		sLog.debug("Adding files to archive");
		for (File f : files) {
			FileInputStream fis = new FileInputStream(f);
			byte[] bytes = new byte[fis.available()];
			fis.read(bytes);			
			fis.close();
			
			String name = f.getName();
			File parent = f.getParentFile();;
			if (!baseDir.equals(parent)) {
				name = parent.getName() + "/" + name;
			}
			ZipEntry entry = new ZipEntry(transform(name));
			
			jos.putNextEntry(entry);
			jos.write(bytes);		
			sLog.debug("Added file " + f.getName());
		}
		
		
		jos.close();
		return bos.toByteArray();
		
	}
	
	public String transform(String in)
	{
        in = in.replaceAll("[Į]", "I");
        in = in.replaceAll("[į]", "i");
        in = in.replaceAll("[Č]", "C");
        in = in.replaceAll("[č]", "c");
        in = in.replaceAll("[Ą]", "A");
        in = in.replaceAll("[ą]", "a");
        in = in.replaceAll("[Ę]", "E");
        in = in.replaceAll("[ę]", "e");
        in = in.replaceAll("[Ė]", "E");
        in = in.replaceAll("[ė]", "e");
        in = in.replaceAll("[Š]", "S");
        in = in.replaceAll("[š]", "s");
        in = in.replaceAll("[Ų]", "u");
        in = in.replaceAll("[ų]", "u");
        in = in.replaceAll("[Ū]", "U");
        in = in.replaceAll("[ū]", "u");
        in = in.replaceAll("[Ž]", "Z");
        in = in.replaceAll("[ž]", "z");
        return in;
	}
	public DisplayMode getDisplayMode() {
		return mDisplayMode;
	}
	
	public void setDisplayMode(DisplayMode pMode) {
		mDisplayMode = pMode;
	}
	
	public ScheduleOwner getScheduleOwner() {
		return mScheduleOwner;
	}
	
	public void setScheduleOwner(ScheduleOwner pOwner) {
		mScheduleOwner = pOwner;
	}


	public String getStudentId() 
	{
		return mStudentId;
	}

	public void setStudentId(String pStudentId)
	{
		mStudentId = pStudentId;
	}

	public String getTeacherId() 
	{
		return mTeacherId;
	}

	public void setTeacherId(String pTeacherId) 
	{
		mTeacherId = pTeacherId;
	}

	public String getRoomId() 
	{
		return mRoomId;
	}

	public void setRoomId(String pRoomId) 
	{
		mRoomId = pRoomId;
	}

	public String getGroupId() 
	{
		return mGroupId;
	}

	public void setGroupId(String pGroupId) 
	{
		mGroupId = pGroupId;
	}
	
	public boolean isEmpty() {
		return getInitial() == null;
	}
	

	/*
	public static void main(String[] args) throws Exception {
		ResultsBean rb = new ResultsBean();
		byte[] bytes = rb.getAsZip();
		
		FileOutputStream fos = new FileOutputStream("C:/out.zip");
		fos.write(bytes);
		fos.close();		
	}
	*/
	
}
