/*
 * Copyright 2010-2013 napile.org
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/*
 * @author max
 */
package org.napile.idea.plugin.codeInsight.toolWindow.codewindow;

import java.awt.BorderLayout;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.Collections;

import javax.swing.JPanel;

import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.napile.asm.LangVersion;
import org.napile.asm.io.AsmWriterOption;
import org.napile.asm.io.xml.out.AsmTextTextWriter;
import org.napile.asm.tree.members.ClassNode;
import org.napile.compiler.NapileFileType;
import org.napile.compiler.analyzer.AnalyzeExhaust;
import org.napile.compiler.codegen.CompilationErrorHandler;
import org.napile.compiler.codegen.GenerationState;
import org.napile.compiler.codegen.Progress;
import org.napile.idea.plugin.codeInsight.toolWindow.EditorLocation;
import org.napile.idea.plugin.module.ModuleAnalyzerUtil;
import org.napile.idea.plugin.util.LongRunningReadTask;
import com.intellij.openapi.Disposable;
import com.intellij.openapi.application.Result;
import com.intellij.openapi.command.WriteCommandAction;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.editor.EditorFactory;
import com.intellij.openapi.fileEditor.FileEditorManager;
import com.intellij.openapi.project.Project;
import com.intellij.util.Alarm;

public class TextBytecodeToolwindow extends JPanel implements Disposable
{
	private static final String DEFAULT_TEXT =
			"<!--\n" +
					"Generated bytecode for Napile source file.\n" +
					"No Napile source file is opened.\n" +
					"-->";

	private static final int UPDATE_DELAY = 1000;

	public class UpdateToolWindowTask extends LongRunningReadTask<EditorLocation, String>
	{
		@Nullable
		@Override
		protected EditorLocation prepareRequestInfo()
		{
			EditorLocation location = EditorLocation.fromEditor(FileEditorManager.getInstance(myProject).getSelectedTextEditor(), myProject);
			if(location.getEditor() == null || location.getFile() == null)
			{
				return null;
			}

			return location;
		}

		@NotNull
		@Override
		protected EditorLocation cloneRequestInfo(@NotNull EditorLocation location)
		{
			EditorLocation newLocation = super.cloneRequestInfo(location);
			assert location.equals(newLocation) : "cloneRequestInfo should generate same location object";
			return newLocation;
		}

		@Override
		protected void hideResultOnInvalidLocation()
		{
			setText(DEFAULT_TEXT);
		}

		@Nullable
		@Override
		protected String processRequest(@NotNull EditorLocation editorLocation)
		{
			GenerationState state;
			try
			{
				AnalyzeExhaust binding = ModuleAnalyzerUtil.lastAnalyze(editorLocation.getFile());
				//            AnalyzingUtils.throwExceptionOnErrors(binding);
				if(binding.isError())
				{
					return printStackTraceToString(binding.getError());
				}
				state = new GenerationState(myProject, Progress.DEAF, binding, Collections.singletonList(editorLocation.getFile()));
				state.compileAndGenerate(CompilationErrorHandler.THROW_EXCEPTION);
			}
			catch(Exception e)
			{
				return printStackTraceToString(e);
			}

			StringBuilder answer = new StringBuilder();

			AsmTextTextWriter writer = new AsmTextTextWriter();
			writer.enableOption(AsmWriterOption.INSTRUCTION_INDEX_IN_COMMENT);
			for(ClassNode classNode : state.getClassNodes().values())
				answer.append(writer.write(LangVersion.CURRENT, classNode));

			return answer.toString();
		}

		private String printStackTraceToString(Throwable e)
		{
			StringWriter out = new StringWriter(1024);
			e.printStackTrace(new PrintWriter(out));
			return out.toString().replace("\r", "");
		}

		@Override
		protected void onResultReady(@NotNull EditorLocation requestInfo, final String resultText)
		{
			Editor editor = requestInfo.getEditor();
			assert editor != null;

			if(resultText == null)
			{
				return;
			}

			setText(resultText);
		}
	}


	private final Editor myEditor;
	private final Alarm myUpdateAlarm;

	private final Project myProject;
	private UpdateToolWindowTask currentTask;

	public TextBytecodeToolwindow(Project project)
	{
		super(new BorderLayout());
		myProject = project;
		myEditor = EditorFactory.getInstance().createEditor(EditorFactory.getInstance().createDocument(""), project, NapileFileType.INSTANCE, true);
		add(myEditor.getComponent());

		myUpdateAlarm = new Alarm(Alarm.ThreadToUse.SWING_THREAD, this);
		myUpdateAlarm.addRequest(new Runnable()
		{
			@Override
			public void run()
			{
				myUpdateAlarm.addRequest(this, UPDATE_DELAY);
				UpdateToolWindowTask task = new UpdateToolWindowTask();
				task.init();

				if(task.shouldStart(currentTask))
				{
					currentTask = task;
					currentTask.run();
				}
			}
		}, UPDATE_DELAY);

		setText(DEFAULT_TEXT);
	}

	private void setText(final String text)
	{
		new WriteCommandAction(myProject)
		{
			@Override
			protected void run(Result result) throws Throwable
			{
				myEditor.getDocument().setText(text);
			}
		}.execute();
	}

	@Override
	public void dispose()
	{
		EditorFactory.getInstance().releaseEditor(myEditor);
	}
}

@@ -1088,51 +1088,8 @@
 de;%0A
-import org.napile.compiler.NapileFileType;%0A
 impo
@@ -1766,24 +1766,81 @@
 torManager;%0A
+import com.intellij.openapi.fileTypes.PlainTextFileType;%0A
 import com.i
@@ -4817,22 +4817,25 @@
 roject, 
-Napile
+PlainText
 FileType

use plain text file type (some issue with IOBE)