package de.ugoe.cs.swe.exercises.exercisesheet;

import java.io.File;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.GregorianCalendar;

import org.eclipse.core.filesystem.EFS;
import org.eclipse.core.filesystem.IFileStore;
import org.eclipse.nebula.widgets.datechooser.DateChooserCombo;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.SashForm;
import org.eclipse.swt.dnd.DND;
import org.eclipse.swt.dnd.DragSource;
import org.eclipse.swt.dnd.DragSourceEvent;
import org.eclipse.swt.dnd.DragSourceListener;
import org.eclipse.swt.dnd.DropTarget;
import org.eclipse.swt.dnd.DropTargetAdapter;
import org.eclipse.swt.dnd.DropTargetEvent;
import org.eclipse.swt.dnd.TextTransfer;
import org.eclipse.swt.dnd.Transfer;
import org.eclipse.swt.events.ModifyEvent;
import org.eclipse.swt.events.ModifyListener;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.FileDialog;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableColumn;
import org.eclipse.swt.widgets.TableItem;
import org.eclipse.swt.widgets.Text;
import org.eclipse.ui.IEditorInput;
import org.eclipse.ui.IEditorRegistry;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.PartInitException;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.ide.FileStoreEditorInput;

import de.ugoe.cs.swe.exercises.exercise.Exercise;
import de.ugoe.cs.swe.exercises.exercise.ExerciseSVN;
import de.ugoe.cs.swe.exercises.lecture.GUITreeView;
import de.ugoe.cs.swe.exercises.misc.CKeyword;
import de.ugoe.cs.swe.exercises.misc.KeywordsCompositeExtender;

public class ExerciseSheetComposite extends Composite {

	private ExerciseSheet selected = null;
	private KeywordsCompositeExtender keywordsExtender;
	private Text sheetNumberText;
	private Text complexityText;
	private Table currentExercisesTable;
	private Table possibleExercisesTable;
	private Label lectureEventLabel;
	private Button examinationCheck;
	private TableColumn currentTitle;
	private TableColumn currentComplexity;
	private TableColumn possibleTitle;
	private TableColumn possibleComplexity;
	private Composite lectureEventFields;
	private SashForm sashForm;
	private Button generateButton;
	private Button pdfButton;
	private Label lblOfExercises;
	private Text numOfExercisesText;
	private Button delPDF;
	private SashForm sashForm_1;
	private Button previewButton;
	private Button solutionButton;
	private Label lblLecureEvent;
	private Label lblDueDate;
	private DateChooserCombo dueDateChooserCombo;

	class ExerciseDragger implements DragSourceListener {
		Table viewer;
		ExerciseSheetComposite composite;
		String data;
		boolean remove;

		public ExerciseDragger(ExerciseSheetComposite composite, Table viewer,
				boolean remove) {
			this.viewer = viewer;
			this.composite = composite;
			this.remove = remove;
		}

		public void dragStart(DragSourceEvent event) {
			event.doit = (selected != null);
		}

		public void dragSetData(DragSourceEvent event) {
			data = "";
			TableItem[] sel = viewer.getSelection();

			for (int i = 0; i < sel.length; i++) {
				Exercise exercise = (Exercise) sel[i].getData();
				data += String.valueOf(exercise.getId()) + ",";
			}

			event.data = data;
		}

		public void dragFinished(DragSourceEvent event) {
			if (event.detail == DND.DROP_MOVE && remove) {
				String[] exerciseList = data.split(",");
				Exercise itemToDelete;
				for (int i = 0; i < exerciseList.length; i++) {
					itemToDelete = Exercise.getItem(Integer
							.parseInt(exerciseList[i]));
					selected.removeExercise(itemToDelete);
				}
				composite.refreshData();
			}
		}
	}

	class ExerciseDropper extends DropTargetAdapter {
		ExerciseSheetComposite composite;
		boolean add;

		public ExerciseDropper(ExerciseSheetComposite composite, boolean add) {
			this.composite = composite;
			this.add = add;
		}

		public void dragOver(DropTargetEvent event) {
			event.feedback = DND.FEEDBACK_SCROLL | DND.FEEDBACK_SELECT;
		}

		public void drop(DropTargetEvent event) {
			if (event.data == null) {
				event.detail = DND.DROP_NONE;
				return;
			}
			if (!add)
				return;
			String[] exerciseList = ((String) event.data).split(",");
			Exercise itemToAdd;
			for (int i = 0; i < exerciseList.length; i++) {
				itemToAdd = Exercise.getItem(Integer.parseInt(exerciseList[i]));
				selected.addExercise(itemToAdd);
			}
			composite.refreshData();
		}
	}

	/**
	 * Create the composite.
	 * 
	 * @param this
	 * @param style
	 */
	public ExerciseSheetComposite(Composite parent, int style) {
		super(parent, SWT.NONE);
		setLayout(new GridLayout(4, true));

		lectureEventFields = new Composite(this, SWT.NONE);
		lectureEventFields.setLayout(new GridLayout(2, false));
		GridData gridData_1 = new GridData(SWT.FILL, SWT.TOP, false, false,
				2, 6);
		gridData_1.heightHint = 201;
		lectureEventFields.setLayoutData(gridData_1);

		Label sheetLabel = new Label(lectureEventFields, SWT.NONE);
		sheetLabel.setLayoutData(new GridData(SWT.LEFT, SWT.TOP, false,
				false, 1, 1));
		sheetLabel.setText("Sheet #");

		sheetNumberText = new Text(lectureEventFields, SWT.BORDER);
		sheetNumberText.setLayoutData(new GridData(SWT.FILL, SWT.TOP, false,
				false, 1, 1));
				
				lblLecureEvent = new Label(lectureEventFields, SWT.NONE);
				lblLecureEvent.setText("Lecure Event:");
		
				lectureEventLabel = new Label(lectureEventFields, SWT.NONE);
				lectureEventLabel.setLayoutData(new GridData(SWT.FILL, SWT.TOP,
						true, false, 1, 1));
				lectureEventLabel.setText("Lecture Event");

		Label complexityLabel = new Label(lectureEventFields, SWT.NONE);
		complexityLabel.setText("Maximum Complexity:");

		complexityText = new Text(lectureEventFields, SWT.BORDER);
		complexityText.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false, 1, 1));

		lblOfExercises = new Label(lectureEventFields, SWT.NONE);
		lblOfExercises.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false,
				false, 1, 1));
		lblOfExercises.setText("# of exercises");

		numOfExercisesText = new Text(lectureEventFields, SWT.BORDER);
		numOfExercisesText.setLayoutData(new GridData(SWT.FILL, SWT.CENTER,
				true, false, 1, 1));
		
		lblDueDate = new Label(lectureEventFields, SWT.NONE);
		lblDueDate.setText("Due Date:");
		
		dueDateChooserCombo = new DateChooserCombo(lectureEventFields, SWT.NONE);
		dueDateChooserCombo.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1));

		examinationCheck = new Button(lectureEventFields, SWT.CHECK);
		examinationCheck.addSelectionListener(new SelectionAdapter() {
			@Override
			public void widgetSelected(SelectionEvent e) {
				selected.setExamination(examinationCheck.getSelection());
			}
		});
		examinationCheck.setSelection(true);
		examinationCheck.setText("is Examination");
		new Label(lectureEventFields, SWT.NONE);

		sashForm = new SashForm(lectureEventFields, SWT.NONE);
		sashForm.setLayoutData(new GridData(SWT.FILL, SWT.BOTTOM, false, false,
				2, 1));

		final Shell shell = parent.getShell();
		pdfButton = new Button(sashForm, SWT.NONE);
		pdfButton.setText("Sheet to PDF");
		pdfButton.addSelectionListener(new SelectionAdapter() {
			@Override
			public void widgetSelected(SelectionEvent e) {

				FileDialog fd = new FileDialog(shell, SWT.SAVE);
				fd.setText("Save exercise sheet");
				String[] filterExt = { "*.pdf" };
				fd.setFilterExtensions(filterExt);
				String path = fd.open();
				String newFileName = selected.getLectureEvent().getLecture()
						.getName()
						+ " Blatt "
						+ selected.getNumber()
						+ " "
						+ selected.getLectureEvent().getSemesterString()
						+ String.valueOf(selected.getLectureEvent()
								.getSemester());
				PdfGenerator.generatePdf(selected, path, true, true);
				ExerciseSVN.SVNAdd(fd.getFileName(), newFileName);

				ExerciseSheetPDFDialog dialog = new ExerciseSheetPDFDialog(
						shell, path);

				dialog.open();

			}
		});

		solutionButton = new Button(sashForm, SWT.NONE);
		solutionButton.setText("Solutionsheet to PDF");
		solutionButton.addSelectionListener(new SelectionAdapter() {
			@Override
			public void widgetSelected(SelectionEvent e) {

				FileDialog fd = new FileDialog(shell, SWT.SAVE);
				fd.setText("Save solution sheet");
				String[] filterExt = { "*.pdf" };
				fd.setFilterExtensions(filterExt);
				String path = fd.open();
				String newFileName = selected.getLectureEvent().getLecture()
						.getName()
						+ " Blatt "
						+ selected.getNumber()
						+ " LÖSUNG "
						+ selected.getLectureEvent().getSemesterString()
						+ String.valueOf(selected.getLectureEvent()
								.getSemester());
				PdfGenerator.generatePdf(selected, path, true, false);
				ExerciseSVN.SVNAdd(fd.getFileName(), newFileName);

				ExerciseSheetPDFDialog dialog = new ExerciseSheetPDFDialog(
						shell, path);

				dialog.open();

			}
		});

		sashForm.setWeights(new int[] { 1, 1 });

		sashForm_1 = new SashForm(lectureEventFields, SWT.NONE);
		sashForm_1.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false,
				false, 2, 1));

		delPDF = new Button(sashForm_1, SWT.NONE);
		delPDF.addSelectionListener(new SelectionAdapter() {
			@Override
			public void widgetSelected(SelectionEvent e) {

				String path = selected.getLectureEvent().getLecture().getName()
						+ " Blatt "
						+ selected.getNumber()
						+ " "
						+ selected.getLectureEvent().getSemesterString()
						+ String.valueOf(selected.getLectureEvent()
								.getSemester());

				String pathSol = selected.getLectureEvent().getLecture()
						.getName()
						+ " Blatt "
						+ selected.getNumber()
						+ " LÖSUNG "
						+ selected.getLectureEvent().getSemesterString()
						+ String.valueOf(selected.getLectureEvent()
								.getSemester());

				File fileTest = new File(ExerciseSVN.SVNpath
						+ "exercisesheets/" + path.replaceAll(" ", "_")
						+ ".pdf");
				File fileTestSol = new File(ExerciseSVN.SVNpath
						+ "exercisesheets/" + pathSol.replaceAll(" ", "_")
						+ ".pdf");

				if (fileTest.exists() || fileTestSol.exists()) {
					ExerciseSheetPDFDeleteDialog dialog = new ExerciseSheetPDFDeleteDialog(
							shell, path, pathSol);
					dialog.open();
				} else {
					ExerciseSheetErrorDialog error = new ExerciseSheetErrorDialog(
							shell);
					error.open();
				}
			}
		});
		delPDF.setText("Remove PDF revision");

		previewButton = new Button(sashForm_1, SWT.NONE);
		previewButton.addSelectionListener(new SelectionAdapter() {
			@Override
			public void widgetSelected(SelectionEvent e) {
				PdfGenerator.generatePdf(selected, System
						.getProperty("java.io.tmpdir")
						+ "/tempPDFfileForPreview.pdf", false, true);
				File f = new File(System.getProperty("java.io.tmpdir")
						+ "/tempPDFfileForPreview.pdf");

				IWorkbenchPage activePage = PlatformUI.getWorkbench()
						.getActiveWorkbenchWindow().getActivePage();

				final IFileStore fileStore = EFS.getLocalFileSystem().getStore(
						f.toURI());

				IEditorInput editorInput = new FileStoreEditorInput(fileStore);
				try {
					activePage.openEditor(editorInput,
							IEditorRegistry.SYSTEM_EXTERNAL_EDITOR_ID);
				} catch (PartInitException e1) {
					e1.printStackTrace();
				}
			}
		});
		previewButton.setText("PDF Preview");

		sashForm_1.setWeights(new int[] { 1, 1 });
		complexityText.addModifyListener(new ModifyListener() {
			public void modifyText(ModifyEvent e) {
				selected.setComplexityValue((int) Integer
						.parseInt(complexityText.getText()));

			}
		});
		sheetNumberText.addModifyListener(new ModifyListener() {
			public void modifyText(ModifyEvent e) {
				// TODO: Ueberpruefung, ob die Eingabe eine Zahl war
				selected.setNumber((int) Integer.parseInt(sheetNumberText
						.getText()));
				GUITreeView.getTree().getSelection()[0].setText("Sheet "
						+ sheetNumberText.getText());
			}
		});

		Composite keywordComposite = new Composite(this, SWT.NONE);
		keywordComposite.setLayout(new GridLayout(2, false));
		GridData gridData = new GridData(SWT.FILL, SWT.FILL, true, false, 2, 6);
		gridData.heightHint = 186;
		keywordComposite.setLayoutData(gridData);
		keywordsExtender = new KeywordsCompositeExtender(keywordComposite,
				CKeyword.EXERCISESHEET);
		gridData.heightHint = 306;

		Label currentExerciseLabel = new Label(this, SWT.NONE);
		currentExerciseLabel.setText("Current Exercises:");

		generateButton = new Button(this, SWT.NONE);
		generateButton.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false,
				false, 1, 1));
		generateButton.addSelectionListener(new SelectionAdapter() {

			public void widgetSelected(SelectionEvent e) {
				ExerciseSheet.deleteDuplicates(selected.getId());
				generateSheet();
				refreshData();
				save();
			}
		});
		generateButton.setText("Auto-Assign Exercises");

		Label possibleExerciseLabel = new Label(this, SWT.NONE);
		possibleExerciseLabel.setText("Possible Exercises:");
		new Label(this, SWT.NONE);

		currentExercisesTable = new Table(this, SWT.BORDER | SWT.FULL_SELECTION);
		currentExercisesTable.setLayoutData(new GridData(SWT.FILL, SWT.FILL,
				false, true, 2, 1));
		currentExercisesTable.setHeaderVisible(true);
		currentExercisesTable.setLinesVisible(true);

		currentTitle = new TableColumn(currentExercisesTable, SWT.NONE);
		currentTitle.setWidth(200);
		currentTitle.setText("Title");

		currentComplexity = new TableColumn(currentExercisesTable, SWT.NONE);
		currentComplexity.setResizable(false);
		currentComplexity.setWidth(20);
		currentComplexity.setText("Complexity");

		possibleExercisesTable = new Table(this, SWT.BORDER
				| SWT.FULL_SELECTION);
		possibleExercisesTable.setLayoutData(new GridData(SWT.FILL, SWT.FILL,
				true, true, 2, 1));
		possibleExercisesTable.setHeaderVisible(true);
		possibleExercisesTable.setLinesVisible(true);

		possibleTitle = new TableColumn(possibleExercisesTable, SWT.NONE);
		possibleTitle.setWidth(200);
		possibleTitle.setText("Title");

		possibleComplexity = new TableColumn(possibleExercisesTable, SWT.NONE);
		possibleComplexity.setResizable(false);
		possibleComplexity.setWidth(20);
		possibleComplexity.setText("Complexity");

		Transfer[] types = new Transfer[] { TextTransfer.getInstance() };
		int operations = DND.DROP_MOVE;

		final DragSource sourceCurrent = new DragSource(currentExercisesTable,
				operations);
		sourceCurrent.setTransfer(types);
		sourceCurrent.addDragListener(new ExerciseDragger(this,
				currentExercisesTable, true));

		DropTarget targetPossible = new DropTarget(possibleExercisesTable,
				operations);
		targetPossible.setTransfer(types);
		targetPossible.addDropListener(new ExerciseDropper(this, false));

		final DragSource sourcePossible = new DragSource(
				possibleExercisesTable, operations);
		sourcePossible.setTransfer(types);
		sourcePossible.addDragListener(new ExerciseDragger(this,
				possibleExercisesTable, false));

		DropTarget targetCurrent = new DropTarget(currentExercisesTable,
				operations);
		targetCurrent.setTransfer(types);
		targetCurrent.addDropListener(new ExerciseDropper(this, true));
	}

	public void load(ExerciseSheet exerciseSheet) {
		this.selected = exerciseSheet;
		refreshData();
	}

	public void save() {
		if (this.selected == null)
			return;
		selected.setNumber(Integer.parseInt(sheetNumberText.getText()));
		selected.setNumOfExercises(Integer.parseInt(numOfExercisesText
				.getText()));
		String[] dateComponents = dueDateChooserCombo.getText().split("\\.");
		if (dateComponents.length == 3) {
			String year = dateComponents[2].trim();
			String month = dateComponents[1].trim();
			String day = dateComponents[0].trim();
			if ((year.length() > 0) && (month.length() > 0) && (day.length() > 0)) {
				Calendar dueDate = new GregorianCalendar();
				dueDate.set(Calendar.DAY_OF_MONTH, Integer.parseInt(day));
				dueDate.set(Calendar.MONTH, Integer.parseInt(month)-1);
				dueDate.set(Calendar.YEAR, Integer.parseInt(year));
				long timestamp = (dueDate.getTimeInMillis() / 1000);
				int dueDateTimestamp = (int) timestamp;
				
				selected.setDueDate(dueDateTimestamp);
			}
		}
		selected.save();
	}

	public void refreshData() {
		ExerciseSheet exerciseSheet = this.selected;
		keywordsExtender.load(exerciseSheet);
		sheetNumberText.setText("" + exerciseSheet.getNumber());
		complexityText.setText("" + exerciseSheet.getComplexityValue());
		
		Calendar dueDate = new GregorianCalendar();
		long timestamp = ((long) exerciseSheet.getDueDate()) * 1000;
		dueDate.setTimeInMillis(timestamp);
		dueDateChooserCombo.setValue(dueDate.getTime());
		numOfExercisesText.setText(String.valueOf(exerciseSheet
				.getNumOfExercises()));
		examinationCheck.setSelection(exerciseSheet.isExamination());
		lectureEventLabel.setText(exerciseSheet.getLectureEvent().getLecture()
				.getName()
				+ " "
				+ exerciseSheet.getLectureEvent().getSemesterString()
				+ exerciseSheet.getLectureEvent().getSemester());

		ArrayList<Exercise> exercises = exerciseSheet.getExercises();
		TableItem item;
		currentExercisesTable.removeAll();
		for (int i = 0; i < exercises.size(); i++) {
			item = new TableItem(currentExercisesTable, SWT.NONE);
			item.setData(exercises.get(i));
			item.setText(0, exercises.get(i).getTitle());
			item.setText(1, "" + exercises.get(i).getComplexity());
		}
		SheetGenerator possibleExercisesGenerator = new SheetGenerator(selected
				.getLectureEvent(), CKeyword.getKeywordsForModel(selected
				.getId(), CKeyword.EXERCISESHEET));

		ArrayList<Exercise> possibleExercises = possibleExercisesGenerator
				.getValidExercises();

		possibleExercises.removeAll(exercises);
		possibleExercisesTable.removeAll();
		for (Exercise exercise : possibleExercises) {
			item = new TableItem(possibleExercisesTable, SWT.NONE);
			item.setData(exercise);
			item.setText(0, exercise.getTitle());
			item.setText(1, "" + exercise.getComplexity());
		}

	}

	@Override
	protected void checkSubclass() {
		// Disable the check that prevents subclassing of SWT components
	}

	private void generateSheet() {
		ExerciseSheet exerciseSheet = selected;
		SheetGenerator generator = new SheetGenerator(exerciseSheet
				.getComplexityValue(), exerciseSheet.getLectureEvent(),
				CKeyword.getKeywordsForModel(exerciseSheet.getId(),
						CKeyword.EXERCISESHEET), Integer
						.parseInt(numOfExercisesText.getText()));
		ArrayList<Exercise> exerciseList = generator.generateExercises();
		for (int i = 0; i < exerciseList.size(); i++) {
			exerciseSheet.addExercise(exerciseList.get(i));
		}
		exerciseSheet.setExerciseMaxRevision(exerciseSheet.returnMaxRevision());

		exerciseSheet.save();
	}
}
