package tvark.model;

import java.io.Serializable;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Collections;
//import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import tvark.old.Property;
import tvark.old.Schedule;
import tvark.old.Student;
import tvark.old.Subject;
import tvark.old.Teacher;
import tvark.old.Room;

public class ScheduleModel implements Serializable {
	
	private static final long serialVersionUID = 1124862758899783671L;

	public static final int NUMBER_OF_DAYS = 5;
	
	private int mLessonsPerDay;	
	private int mRooms;
	private Integer[] mLessonsNumbers;
	private int mPenalty;
	
	private Schedule mOriginalSchedule;
	private Subject[][][] mOriginalSubjectSchedule;
	private Teacher[][][] mOriginalTeacherSchedule;
	private Student[][][][] mOriginalStudentSchedule;
	private Room[][][] mOriginalRoomSchedule;
	
	private List<Lesson>[][] mSchedule;
	private Map<String, List<Lesson>[][]> mStudentSchedule;
	private Map<String, List<Lesson>[][]> mTeacherSchedule;
	private Map<String, List<Lesson>[][]> mRoomSchedule;
	private Map<String, List<Lesson>[][]> mGroupSchedule;
	
	private List<String> mStudentIds;
	private List<String> mTeacherIds;
	private List<String> mRoomIds;
	private List<String> mGroupIds;
	
	public Subject[][][] getSubjectSchedule() 
	{
		return mOriginalSubjectSchedule;
	}
	
	public Integer[] getLessonNumbers() 
	{
		return mLessonsNumbers;		
	}
	
	private static <T> T getField(Object pObject, String pField, Class<T> pType) {
		try {
			Field f = pObject.getClass().getDeclaredField(pField);
			f.setAccessible(true);
			T t = pType.cast(f.get(pObject));
			return t;
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
	}
	
	public ScheduleModel(Schedule pOriginalSchedule, Property pProperty) {
		mOriginalSchedule = pOriginalSchedule;
		mLessonsPerDay = pOriginalSchedule.getLpd();
		mRooms = pOriginalSchedule.getMaxClasses();
		mPenalty = pOriginalSchedule.countPenalty(pProperty);
		
		mOriginalSubjectSchedule = getField(mOriginalSchedule, "SubjectSchedule", Subject[][][].class);
		mOriginalTeacherSchedule = getField(mOriginalSchedule, "TeacherSchedule", Teacher[][][].class);
		mOriginalStudentSchedule = getField(mOriginalSchedule, "StudentSchedule", Student[][][][].class);
		mOriginalRoomSchedule = getField(mOriginalSchedule, "RoomSchedule", Room[][][].class);
		
		calcLessonNumbers();
		calcLessonInfos();
	}
	
	private void calcLessonNumbers() {
		mLessonsNumbers = new Integer[mLessonsPerDay];
		for (int i = 0; i < mLessonsPerDay; ++i) {
			mLessonsNumbers[i] = i + 1;
		}
	}
	
	private static <T> List<T> toList(T[] pArray) {
		List<T> result = new ArrayList<T>();
		for (T t : pArray) {
			if (t != null) {
				result.add(t);
			}
		}
		return result;
	}
	
	@SuppressWarnings("unchecked")
	private List<Lesson>[][] createTT() {
		List<Lesson>[][] result = new List[NUMBER_OF_DAYS][mLessonsPerDay];
		for (int i = 0; i < NUMBER_OF_DAYS; ++i) {
			for (int j = 0; j < mLessonsPerDay; ++j) {
				//result[i][j] = new ArrayList<Lesson>();
			}
		}
		return result;
	}
	
	private void calcLessonInfos() {
		mSchedule = createTT();
		mStudentSchedule = new HashMap<String, List<Lesson>[][]>(); 
		mTeacherSchedule = new HashMap<String, List<Lesson>[][]>();
		mRoomSchedule = new HashMap<String, List<Lesson>[][]>();
		mGroupSchedule = new HashMap<String, List<Lesson>[][]>();
		
		for (int i = 0; i < NUMBER_OF_DAYS; ++i) {
			for (int j = 0; j < mLessonsPerDay; ++j) {
				for (int k = 0; k < mRooms; ++k) {
					if (mOriginalSubjectSchedule[i][j][k] != null) {						
						Teacher teacher = mOriginalTeacherSchedule[i][j][k];
						Subject subject = mOriginalSubjectSchedule[i][j][k];
						Room room = mOriginalRoomSchedule[i][j][k];
						List<Student> students = toList(mOriginalStudentSchedule[i][j][k]);
						int rr = room.getRoom();
					//	String roomId = Integer.toString(k);						
						Lesson lessonInfo = new Lesson(i, j, subject, teacher, students, rr);
						
						addLesson(mSchedule, i, j, lessonInfo);
						//mSchedule[i][j].add(lessonInfo);

						String teacherId = teacher.getName();
						List<Lesson>[][] teacherTT = mTeacherSchedule.get(teacherId);
						if (teacherTT == null) {
							teacherTT = createTT();
							mTeacherSchedule.put(teacherId, teacherTT);
						}
						addLesson(teacherTT, i, j, lessonInfo);
						//teacherTT[i][j].add(lessonInfo);
						
						String roomId = Integer.toString(room.getRoom());
						List<Lesson>[][] roomTT = mRoomSchedule.get(roomId);
						if (roomTT == null) {
							roomTT = createTT();
							mRoomSchedule.put(roomId, roomTT);
						}
						addLesson(roomTT, i, j, lessonInfo);
						//roomTT[i][j].add(lessonInfo);		
						
						for (Student student : students) {
							String studentId = student.getName();
							List<Lesson>[][] studentTT = mStudentSchedule.get(studentId);
							if (studentTT == null) {
								studentTT = createTT();
								mStudentSchedule.put(studentId, studentTT);
							}
							//studentTT[i][j].add(lessonInfo);	
							addLesson(studentTT, i, j, lessonInfo);
						}
						
						Student student = students.iterator().next();
						if (student != null) {
							String groupId = student.getKlass();
							List<Lesson>[][] groupTT = mGroupSchedule.get(groupId);
							if (groupTT == null) {
								groupTT = createTT();
								mGroupSchedule.put(groupId, groupTT);
							}
							//groupTT[i][j].add(lessonInfo);
							addLesson(groupTT, i, j, lessonInfo);
						}
					}
				}
			}
		}
		
		mStudentIds = new ArrayList<String>(mStudentSchedule.keySet());
		mTeacherIds = new ArrayList<String>(mTeacherSchedule.keySet());		
		mGroupIds = new ArrayList<String>(mGroupSchedule.keySet());
		mRoomIds = new ArrayList<String>(mRoomSchedule.keySet());
		
		Collections.sort(mStudentIds);
		Collections.sort(mTeacherIds);
		Collections.sort(mGroupIds);
		Collections.sort(mRoomIds); 
						
	}
	
	private static void addLesson(List<Lesson>[][] pTimeTable, int pDayIndex, int pLessonIndex, Lesson pLessonInfo) {
		List<Lesson> listOfLessons = pTimeTable[pDayIndex][pLessonIndex];
		if (listOfLessons == null) {
			listOfLessons = new ArrayList<Lesson>(1);
			pTimeTable[pDayIndex][pLessonIndex] = listOfLessons;
		}
		listOfLessons.add(pLessonInfo);
	}
	
	public List<Lesson>[][] getSchedule() {
		return mSchedule;
	}
	
	public List<Lesson>[][] getStudentSchedule(String pStudentId) 
	{
		return mStudentSchedule.get(pStudentId);
	}
	
	public List<Lesson>[][] getTeacherSchedule(String pTeacherId) 
	{
		return mTeacherSchedule.get(pTeacherId);
	}
	
	public List<Lesson>[][] getGroupSchedule(String pGroupId) 
	{
		return mGroupSchedule.get(pGroupId);
	}
	
	public List<Lesson>[][] getRoomSchedule(String pRoomId) 
	{
		return mRoomSchedule.get(pRoomId);
	}
	
	public Schedule getOriginalSchedule() 
	{
		return mOriginalSchedule;
	}
	
	public List<String> getStudentIds() 
	{
		return mStudentIds;
	}
	
	public List<String> getTeacherIds() 
	{
		return mTeacherIds;
	}
	
	public List<String> getGroupIds() 
	{
		return mGroupIds;
	}
	
	public List<String> getRoomIds() 
	{
		return mRoomIds;
	}
	
	public int getPenalty() 
	{
		return mPenalty;
	}
	
}
