package edu.fichte.pbi.ide.editors;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.LinkedList;
import java.util.List;

import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.jface.action.StatusLineContributionItem;
import org.eclipse.jface.action.StatusLineManager;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.StyleRange;
import org.eclipse.swt.custom.StyledText;
import org.eclipse.swt.events.KeyEvent;
import org.eclipse.swt.events.KeyListener;
import org.eclipse.swt.events.ModifyEvent;
import org.eclipse.swt.events.ModifyListener;
import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.events.MouseListener;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.FileDialog;
import org.eclipse.ui.IEditorInput;
import org.eclipse.ui.IEditorSite;
import org.eclipse.ui.PartInitException;
import org.eclipse.ui.internal.WorkbenchWindow;
import org.eclipse.ui.part.EditorPart;

import edu.fichte.pbi.ide.ApplicationActionBarAdvisor;
import edu.fichte.pbi.ide.commonsstolen.FileUtils;
import edu.fichte.pbi.prgm.parse.Lexer;
import etinyplugins.commons.swt.UndoRedoImpl;

@SuppressWarnings("restriction")
public class PBIEditor extends EditorPart {

	public static final String ID = "edu.fichte.pbi.ide.pbieditor";
	public StyledText text;
	private IEditorInput input;
	private boolean dirty = false;
	private FileSystemFileEditorInput fileInput;
	private StatusLineContributionItem statusLine;

	@Override
	public void doSave(IProgressMonitor monitor) {
		String content = text.getText();
		File file = fileInput.getFile();
		try {
			FileOutputStream out = new FileOutputStream(file);
			out.write(content.getBytes());
			out.close();
			beClean();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	@Override
	public void doSaveAs() {
		FileDialog fileDialog = new FileDialog(getSite().getShell(), SWT.SAVE);
		fileDialog.setFileName(fileInput.getName());
		fileDialog.setFilterPath(fileInput.getFile().getParent());
		String newFile = fileDialog.open();
		File file = new File(newFile);
		if (!file.exists()) {
			try {
				file.createNewFile();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		FileSystemFileEditorInput fileSystemFileEditorInput = new FileSystemFileEditorInput(
				file);
		setInput(fileSystemFileEditorInput);
		doSave(null);
	}

	@Override
	public boolean isSaveOnCloseNeeded() {
		return true;
	}

	@Override
	public void init(IEditorSite site, IEditorInput input)
			throws PartInitException {
		this.input = input;
		setSite(site);
		setInput(input);
		setPartName(input.getName());
	}

	private void beDirty() {
		dirty = true;
		firePropertyChange(PROP_DIRTY);
	}

	private void beClean() {
		dirty = false;
		firePropertyChange(PROP_DIRTY);
	}

	@Override
	public boolean isDirty() {
		return dirty;
	}

	@Override
	public boolean isSaveAsAllowed() {
		return true;
	}

	@Override
	protected void setInput(IEditorInput input) {
		super.setInput(input);
		this.input = input;
		this.fileInput = (FileSystemFileEditorInput) input;
	}

	public StyledText getText() {
		return text;
	}

	@Override
	public void createPartControl(Composite parent) {
		parent = new Composite(parent, 0);
		parent.setLayout(new FillLayout());

		text = new StyledText(parent, SWT.MULTI | SWT.V_SCROLL);
		text.setAlwaysShowScrollBars(true);
		new UndoRedoImpl(text);
		
		addCurrentPositionTelling();

		readFileContentToEditor();
		text.addModifyListener(new ModifyListener() {

			@Override
			public void modifyText(ModifyEvent e) {
				beDirty();
				reformat();
			}

		});

		// Status Zeilenzugriff merken
		StatusLineManager statusLineManager = ((WorkbenchWindow) getSite()
				.getWorkbenchWindow()).getStatusLineManager();
		statusLine = (StatusLineContributionItem) statusLineManager
				.find(ApplicationActionBarAdvisor.MY_COLROW_TELLER);
	}

	private void addCurrentPositionTelling() {
		text.addKeyListener(new KeyListener() {

			@Override
			public void keyPressed(KeyEvent arg0) {
				updatePositionDisplay();
			}

			@Override
			public void keyReleased(KeyEvent arg0) {
				updatePositionDisplay();
			}
		});

		text.addMouseListener(new MouseListener() {

			@Override
			public void mouseUp(MouseEvent arg0) {
				updatePositionDisplay();
			}

			@Override
			public void mouseDown(MouseEvent arg0) {
				updatePositionDisplay();
			}

			@Override
			public void mouseDoubleClick(MouseEvent arg0) {
				updatePositionDisplay();
			}
		});
	}

	private void updatePositionDisplay() {
		int caretOffset = text.getCaretOffset();
		int lineNo = 1;
		int charNo = 1;
		String content = text.getText();
		for (int n = 0; n < caretOffset; n++) {
			char currentChar = content.charAt(n);
			if (currentChar == '\n') {
				lineNo++;
				charNo = 1;
			} else if (currentChar == '\r') {
			} else {
				charNo++;
			}
		}
		String position = lineNo + "/" + charNo;
		statusLine.setText(position);
	}

	private void reformat() {
		// StyleRange styleRange = new StyleRange();
		// styleRange.start = 0;
		// styleRange.length = 10;
		// styleRange.fontStyle = SWT.BOLD;
		// styleRange.foreground = Display.getCurrent().getSystemColor(
		// SWT.COLOR_BLUE);
		for (StyleRange styleRange : sytaxHighlighting()) {
			text.setStyleRange(styleRange);
		}

	}

	private List<StyleRange> sytaxHighlighting() {
		String text = this.text.getText();
		String tmp = "";
		List<String> knowCommands = new LinkedList<>();
		for (String cmd : Lexer.KNOWN_COMMANDS) {
			knowCommands.add(cmd);
		}
		knowCommands.add("TO");
		knowCommands.add("THEN");
		knowCommands.add("STEP");
		List<StyleRange> retVal = new LinkedList<StyleRange>();
		StyleRange allBlack = new StyleRange();
		allBlack.start = 0;
		allBlack.length = text.length();
		allBlack.foreground = Display.getCurrent().getSystemColor(
				SWT.COLOR_BLACK);
		retVal.add(allBlack);
		global: for (int i = 0; i < text.length(); i++) {
			char actual = text.charAt(i);
			if (actual == ' ' || actual == '\n' || actual == ',') {
				tmp = "";
				continue;
			}
			if (actual == '=' || actual == '/' || actual == '*'
					|| actual == '+' || actual == '-' || actual == '^'
					|| actual == '|' || actual == '&' || actual == '>'
					|| actual == '<') {
				StyleRange styleRange = new StyleRange();
				styleRange.start = i;
				styleRange.length = 1;
				styleRange.fontStyle = SWT.BOLD;
				styleRange.foreground = Display.getCurrent().getSystemColor(
						SWT.COLOR_DARK_RED);
				retVal.add(styleRange);
				tmp = "";
				continue;
			}
			if (actual == '\'') {
				for (int k = i + 1; k < text.length(); k++) {
					if (text.charAt(k) == '\n' || k == text.length() - 1) {
						StyleRange styleRange = new StyleRange();
						styleRange.start = i;
						styleRange.length = k == text.length() - 1 ? k - i + 1
								: k - i;
						styleRange.foreground = Display.getCurrent()
								.getSystemColor(SWT.COLOR_DARK_GREEN);
						retVal.add(styleRange);
						tmp = "";
						i = k;
						continue global;
					}
				}
			}
			if (actual == '\"') {
				for (int k = i + 1; k < text.length(); k++) {
					if (text.charAt(k) == '\"') {
						StyleRange styleRange = new StyleRange();
						styleRange.start = i;
						styleRange.length = k - i + 1;
						styleRange.foreground = Display.getCurrent()
								.getSystemColor(SWT.COLOR_DARK_YELLOW);
						retVal.add(styleRange);
						tmp = "";
						i = k;
						continue global;
					}
				}
			}
			tmp += text.charAt(i);
			for (String cmd : knowCommands) {
				if (tmp.equals(cmd)) {
					StyleRange styleRange = new StyleRange();
					styleRange.start = (i + 1) - cmd.length();
					styleRange.length = cmd.length();
					styleRange.fontStyle = SWT.BOLD;
					styleRange.foreground = Display.getCurrent()
							.getSystemColor(SWT.COLOR_BLUE);
					retVal.add(styleRange);
					tmp = "";
					break;
				}
			}
			char prev = (i == 0 ? ' ' : text.charAt(i - 1));
			if (((actual > 47 && actual < 58))
					&& (prev == ' ' || prev == '\n' || prev == ',' || prev == '(') || prev == '=' || prev == '/' || prev == '*'
					|| prev == '+' || prev == '-' || prev == '^'
					|| prev == '|' || prev == '&' || prev == '>'
					|| prev == '<') {
				for (int k = i; k < text.length(); k++) {
					char c = text.charAt(k);
					if (c < 48 || c > 57) {
						StyleRange styleRange = new StyleRange();
						styleRange.start = i;
						styleRange.length = k - i;
						styleRange.foreground = Display.getCurrent()
								.getSystemColor(SWT.COLOR_DARK_YELLOW);
						retVal.add(styleRange);
						tmp = "";
						i = k;
						continue global;
					}
				}
			}
		}
		return retVal;

	}

	private void readFileContentToEditor() {
		if (input instanceof FileSystemFileEditorInput) {
			fileInput = (FileSystemFileEditorInput) input;
			File file = fileInput.getFile();
			try {
				text.setText(FileUtils.readFileToString(file));
				reformat();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}

	@Override
	public void setFocus() {
		text.setFocus();
	}

	public File getFile() {
		return fileInput.getFile();
	}

}

