/* $Id: WorkspaceWindow.java 393 2011-10-11 12:57:17Z shayashi $ */
package smart_gs.swingui;

import java.awt.AWTEvent;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Frame;
import java.awt.KeyboardFocusManager;
import java.awt.event.WindowEvent;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.Serializable;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;

import javax.swing.JDialog;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JSplitPane;
import javax.swing.JTabbedPane;
import javax.swing.JToolBar;
import javax.swing.Timer;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;

import org.apache.commons.io.FileUtils;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.xml.sax.SAXException;

import smart_gs.GSConstants;
import smart_gs.current_text_search.SearchDialogManager;
import smart_gs.dictionary.DictionaryXML;
import smart_gs.drawing_tool.SpreadCanvas;
import smart_gs.drawing_tool.drawing_mode.Mode;
import smart_gs.drawing_tool.state.DefaultState;
import smart_gs.logical.UsersNoteTree;
import smart_gs.logical.Preference;
import smart_gs.logical.Spread;
import smart_gs.logical.SpreadSelectionListManager;
import smart_gs.logical.SpreadTree;
import smart_gs.menu.export.ExportDialog;
import smart_gs.reasoning_web.logical.GS_RWRepository;
import smart_gs.reasoning_web.swingui.GlobalViewPanel;
import smart_gs.reasoning_web.swingui.ReasoningWebFrame;
import smart_gs.smleditor.swingui.GSEditorFrame;
import smart_gs.smleditor.swingui.GSKeyEventPost;
import smart_gs.smleditor.swingui.GSTabbedPane;
import smart_gs.swingui.toolbar.GSEditorToolBar;
import smart_gs.swingui.toolbar.HistoryToolBar;
import smart_gs.swingui.toolbar.ImageToolBar;
import smart_gs.swingui.toolbar.MoveTreeToolBar;
import smart_gs.swingui.toolbar.action.GSFileFilter;
import smart_gs.util.CanonicalPathString;
import smart_gs.util.GsXMLSaver;
import smart_gs.util.LinkCounter;
import sml_editor.swingui.EditorTextPane;
import webdav.WebDavDownLoadEvent;
import webdav.WebDavListenerAction;
import webdav.WebDavProcessor;

import com.hexidec.ekit.GSHTMLEditorSearchActionListner;

@SuppressWarnings("serial")
public class WorkspaceWindow extends AbstractGSWindow implements GSEditorFrame,
		Serializable {


	private static WorkspaceWindow singleton = new WorkspaceWindow();

	private JPanel mainPanel;
	private JTabbedPane leftPanel;
	private SpreadTreePanel spreadTreePanel;
	private JPanel textDocumentPanel;
	private NorthPanel northPanel;
	private JLabel textDocumentStatusBar;
	private JLabel textDocumentStatusBar2;

	private GSKeyEventPost gsKeyEventPost;
	
	// kazuhiro kobayashi 10/9
	private File currentFile;
	
	//2008/9/6 North Grid
	//更新フラグ
	private static boolean updated = false;
	// 2009/01/23
	// 最後のセーブ状態
	// 0 = ローカル
	// 1 = WebDav
	private static int lastsave = 0;
	
	// 0 normal exit, 1 aborted by user 
	private static int preferenceLoadStatus;

	private static boolean opened = false;
	
	private WebDavDownLoadEvent webDavDownLoadEvent;

	private Mode mode;

	private static boolean makeBackupFile = true;
	
	public static WorkspaceWindow getInstance() {
		return singleton;
	}
	
	public int getPreferenceLoadStatus() {return preferenceLoadStatus;}

	public WorkspaceWindow() {
		super("SMART-GS");
		
		preferenceLoadStatus = Preference.getInstance().load();
		
		if (preferenceLoadStatus !=0) return;

		String imageFolderPath = Preference.getInstance().getImageFolderPathString();
		File imageFolder = new File(imageFolderPath);
		if(!imageFolder.exists()){
			imageFolder.mkdirs();
		} 
		File tempDir = new File(GSConstants.TEMP_PATH);
		tempDir.mkdirs();

		this.enableEvents(AWTEvent.WINDOW_EVENT_MASK);
		this.mainPanel = new JPanel(new BorderLayout());
		this.spreadTreePanel = new SpreadTreePanel();
		this.leftPanel = new JTabbedPane();
		this.leftPanel.addTab("Images", this.spreadTreePanel);
		this.leftPanel.addTab("Notes", new UsersNoteTreePanel());
		this.getContentPane().setLayout(new BorderLayout());

		this.northPanel = new NorthPanel(this);
		this.getContentPane().add(northPanel, BorderLayout.NORTH);

		this.textDocumentPanel = new JPanel(new BorderLayout());
		this.tabbedPane = new WorkspaceTabbedPane();
		this.textDocumentPanel.add(this.tabbedPane, BorderLayout.CENTER);

		JSplitPane mainSplitPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT,
				this.mainPanel, this.textDocumentPanel);

		mainSplitPane.setDividerLocation(300);
		mainSplitPane.setOneTouchExpandable(true);
		JSplitPane splitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT,
				this.leftPanel, mainSplitPane);
		splitPane.setOneTouchExpandable(true);

		this.getContentPane().add(splitPane, BorderLayout.CENTER);
		this.setSize(1000, 700);
		
		if(!Preference.getInstance().getDefaultGsFilePathString().equals("")){
			File defaultGsFile = new File(Preference.getInstance().getDefaultGsFilePathString());
			this.restore(defaultGsFile);
			this.autosave(defaultGsFile);
		} else {
			DictionaryXML.getInstance().init();
		}
		
		KeyboardFocusManager m = KeyboardFocusManager.getCurrentKeyboardFocusManager();
		gsKeyEventPost = new GSKeyEventPost();
		m.addKeyEventPostProcessor(gsKeyEventPost);

	}

	public void save() {
		this.tabbedPane.save();
	}
	public void setSpread(Spread spread) {
		this.setSpread(spread,true);
	}

	public void setSpread(Spread spread,boolean history) {
		this.save();
		super.setSpread(spread);
		this.updateGUI(spread);
		this.tabbedPane.setCaret(0);
		if(history){
			HistoryToolBar historyToolBar = this.northPanel.getHistoryToolBar();
			int scale = this.getSpreadCanvas().imageLabel.scale;
			historyToolBar.addHistory(spread, scale);
		}
		updateMoveToolBar();
	}

	public void updateMoveToolBar(){
		MoveTreeToolBar moveTreeToolBar = this.northPanel.getMoveTreeToolBar();
		if(this.tabbedPane.getSpread() != null){
			moveTreeToolBar.setPathCount(this.tabbedPane.getSpread().getPageViewIndex());
		}
	}
	
	public void setImageSearch(String q){
		spreadTreePanel.search(q);
	}
	
	public Spread getSpreadInTree(int row){
		return spreadTreePanel.getSpreadInTree(row);
	}

	public void close(){
		super.close();
		this.textDocumentPanel.removeAll();
		this.validate();
	}
	public void updateGUI(Spread spread) {
		this.textDocumentPanel.removeAll();
		Component mainPanel = ((WorkspaceTabbedPane) tabbedPane).getMainPanel();
		this.mainPanel.removeAll();
		this.mainPanel.add(mainPanel);
		this.textDocumentPanel.add(this.tabbedPane);
		
		textDocumentStatusBar = new JLabel("");
		JPanel jPanel = new JPanel(new BorderLayout());;
		jPanel.add(textDocumentStatusBar,BorderLayout.PAGE_START);
		this.textDocumentPanel.add(jPanel, BorderLayout.SOUTH);
		this.validate();
	}

	@Override
	public GSTabbedPane createTabbedPane(Spread spread) {
		return new WorkspaceTabbedPane(this, spread);
	}

	public SpreadCanvas getSpreadCanvas() {
		if(this.tabbedPane == null) {
			return null;
		} else {
			return ((WorkspaceTabbedPane) this.tabbedPane).getSpreadCanvas();
		}
	}


	public void setEditorToolBar(JToolBar toolbar) {

	}

	public void setEditorTextPane(EditorTextPane textPane) {
		textPane.setSearchAction(new GSHTMLEditorSearchActionListner(){
			public void actionPerformed() {
				SearchDialogManager.setGSEditorToolBar(WorkspaceWindow.getInstance().getGSEditorToolBar());
				SearchDialogManager.visible();				
			}
		});
		this.tabbedPane.setEditorTextPane(textPane);
	}

	public 	GSEditorToolBar getGSEditorToolBar(){
		return this.tabbedPane.getGSEditorToolBar();
	}

	public Spread getSpread() {
		return ((WorkspaceTabbedPane) this.tabbedPane).getSpread();
	}

	public Frame getFrame() {
		return this;
	}

	public void restore(File file) {
		// kazuhiro kobayashi 10/9
		this.currentFile = file;
		if (file.exists()==false) {
			JOptionPane.showMessageDialog(this, file.getName() + " does not exist\n");
			return;
		}
		DocumentBuilder builder;
		Document document;
		try {
			builder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
			if(file.getName().endsWith(".gsx")) {
				ZipFile gsxFile = new ZipFile(file);
				ZipEntry gsxSpread = gsxFile.getEntry("spread.xml");
				if (gsxSpread==null){
					JOptionPane.showMessageDialog(this, file.getName() + ": Invalid gsx file.");
					return;
				}
				document = builder.parse(gsxFile.getInputStream(gsxSpread));
				gsxFile.close();
			} else {
				document = builder.parse(file);
			}
			Element rootElement = document.getDocumentElement();
			String counterValue = rootElement.getAttribute("counter");
			if(counterValue != null){
				try{
					LinkCounter.setID(Integer.parseInt(counterValue));
				}catch(NumberFormatException e){}
			}
			this.setTitle(file.getName() + " - SMART-GS");

			ReasoningWebFrame.getInstance().initializeContentsAndFrame();
			Element spreadElement = (Element) rootElement.getElementsByTagName(
					"spreadTree").item(0);
			SpreadTree.getInstance().restore(spreadElement);
			// 20070926 shimizu wrote;
			// 2011.01.03 shayashi changed　for upper-compatibility
			Element usersNoteElement = (Element) rootElement
					.getElementsByTagName("usersNoteTree").item(0);
			UsersNoteTree.getInstance().clear();
			UsersNoteTree.getInstance().restore(usersNoteElement);
			Element rwElement = (Element) rootElement.getElementsByTagName(
					"reasoning_web").item(0);
			GS_RWRepository.getInstance().restore(rwElement);
			Element sslists = (Element) rootElement.getElementsByTagName(
					"spreadSelectionLists").item(0);
			if (sslists != null) SpreadSelectionListManager.getInstance().restore(sslists);
			//2009/04/22 North Grid
			if( GS_RWRepository.getInstance().getBackgroundFilePath() != null &&
					GS_RWRepository.getInstance().getBackgroundFilePath().length() > 0 ){
				GlobalViewPanel.getInstance().setBackground(new File(GS_RWRepository.getInstance().getBackgroundFilePath()));
			}
			setUpdated(false);
			DictionaryXML.getInstance().load(file);
			DictionaryXML.getInstance().write();
			DictionaryXML.getInstance().setWarning(false);
		} catch (ParserConfigurationException e) {
			e.printStackTrace();
		} catch (SAXException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		this.tabbedPane.clear();
		this.tabbedPane.validate();
		this.tabbedPane.repaint();
		this.validate();
	}

	//2009/01/23 North Grid
	public boolean saveAll() {
		return saveAll(null);
	}
	public boolean saveAll(File file) {
		this.tabbedPane.save();
		try {
			Document document = DocumentBuilderFactory.newInstance()
					.newDocumentBuilder().newDocument();
			Element rootElement = document.createElement("rootElement");
			rootElement.setAttribute("counter", String.valueOf(LinkCounter.intValue()));
			document.appendChild(rootElement);
			SpreadTree.getInstance().save(document, rootElement);
			// 20080926 shimizu wrote;
			UsersNoteTree.getInstance().save(document, rootElement);
			GS_RWRepository.getInstance().save(document, rootElement);
			// 20101031 shayashi added
			SpreadSelectionListManager.getInstance().save(document, rootElement);

			// 2011/07/10 kukita added
			
			
			if(file == null){
				file = this.currentFile;
				// 2007/10/7 kazuhiro kobayashi
				String currentDirectory = Preference.getInstance()
						.getGsFolderPathString();
				File directory = new File(currentDirectory);
				JFileChooser chooser = new JFileChooser(directory);
				// 2007/10/9 kazuhiro kobayahsi
				if (this.currentFile != null) {
					chooser.setSelectedFile(this.currentFile);
				}
				File file000 = chooser.getCurrentDirectory();
				chooser.setFileFilter(new GSFileFilter());
				String selectedFileName = "";
				while (!selectedFileName.endsWith(".gsx")) {
					int input = chooser.showSaveDialog(WorkspaceWindow.getInstance());
					if (input == JFileChooser.CANCEL_OPTION) {
						return false;
					}
					file = chooser.getSelectedFile();
					selectedFileName = file.getName();
					if (!selectedFileName.endsWith(".gsx")) {
						JOptionPane.showMessageDialog(null, "File name must ends with .gsx");
						chooser.setSelectedFile(new File(selectedFileName + ".gsx"));
					}
				}
			}
			String path = CanonicalPathString.get(file);
//			if (!path.endsWith(".gs")) {
//				path += ".gs";
//			}
			//2007/12/3 kazuhiro kobayshi
			new GsXMLSaver(document, path).save();
			
			//2008/9/6 North Grid
			setUpdated(false);
			return true;
		} catch (ParserConfigurationException e) {
			e.printStackTrace();
			return false;
		}
	}

	public void autosave(File file) {
		int autoSaveInterval = 10; // minutes
		Timer timer;
		
		timer = new Timer(1000 * 60 * autoSaveInterval, new AutosaveAction(file));
		timer.start();
	}

	public void exit() {
		// 2007/10/23 kazuhiro kobayashi
		int input ;

		//2008/9/5 North Grid
		//更新時に確認ダイアログを表示する仕組みを追加
		boolean notcofirm = false;
		if( isUpdated() ){
			String filename = null;
			if(lastsave == 0){
				if(this.currentFile != null){
					filename = this.currentFile.getName();
				}
			}else{
				WebDavDownLoadEvent webDavDownLoadEvent = this.getWebDavDownLoadEvent();
				if(webDavDownLoadEvent != null){
					filename = webDavDownLoadEvent.getDownloaname();
				}
			}
			input = JOptionPane.showConfirmDialog(this, 
					(filename == null ? 
							"Save the edited contents?" :
							"\""+ filename + "\"   Save this file?")
					);

			if (input == JOptionPane.OK_OPTION) {
				if(this.getLastsave() == 0){
					if( this.saveAll() == false ) return;
				}else{
					WebDavListenerAction webDavListenerAction = new WebDavListenerAction();
					webDavListenerAction.save();
				}
			} else if (input == JOptionPane.NO_OPTION) {

			} else if (input == JOptionPane.CANCEL_OPTION) {
				return;
			}
			//2008/9/5 North Grid
			//保存後の確認ダイアログは表示しないよう修正
			notcofirm = true;
		}
		if( notcofirm == false ){
			input = JOptionPane.showConfirmDialog(this, "Exit SMART-GS?");
			if (input != JOptionPane.OK_OPTION) {
				return;
			}
		}
		Preference.getInstance().save();
		//20081031 North Grid Removed
		//SpreadTree.getInstance().saveLine();
		this.tabbedPane.save();
		unlock();
		System.exit(0);
	}
	public void unlock(){
		WebDavDownLoadEvent oldWebDavDownLoadEvent = getWebDavDownLoadEvent();
		if(oldWebDavDownLoadEvent != null){
			String unlockpath = oldWebDavDownLoadEvent.getDownloadpath();
			String unlockname = oldWebDavDownLoadEvent.getDownloaname();
			String locktoken = oldWebDavDownLoadEvent.getLockToken();
			WebDavProcessor webDavProcessor = WebDavProcessor.getInstance();
			if(webDavProcessor == null){
            	JOptionPane.showMessageDialog(
						new JFrame() , "It failed in login WebDav." , "fatal" ,
						JOptionPane.ERROR_MESSAGE
					);
            	return;
			}
			try {
				webDavProcessor.unlock(unlockpath, unlockname, locktoken);
			} catch (IOException e1) {
				e1.printStackTrace();
			}
		}
		File tempDir = new File(GSConstants.TEMP_PATH);
		tempDir.delete();
		setWebDavDownLoadEvent(null);
	}
	
	
	public void export() {
		if(this.tabbedPane.isAvailable()){
			this.tabbedPane.save();
		}
		JDialog frame = new ExportDialog(this.currentFile);	
		frame.setVisible(true);
	}

	@Override
	protected void processWindowEvent(WindowEvent e) {
		if (e.getID() == WindowEvent.WINDOW_CLOSING) {
			this.exit();
		}
	}
	public void tabbedPaneSave(){
		synchronized (tabbedPane) {
			this.tabbedPane.save();
		}
	}
	
	public boolean isAlt() {
		return gsKeyEventPost.isAlt();
	}
	public boolean isCtrl() {
		return gsKeyEventPost.isCtrl();
	}
	public boolean isShift() {
		return gsKeyEventPost.isShift();
	}
	public boolean onlyOneOfAltCtrlShiftIsPressed (){
		return isAlt() ^ isCtrl() ^ isShift();
	}
	public void setStatusBarSource(String statusmessage){
		if (!isTabbedPaneAvailable()){
			JOptionPane.showMessageDialog(null, "Source: " + statusmessage);
			textDocumentStatusBar = new JLabel();
		}
		textDocumentStatusBar.setForeground(Color.RED);
		textDocumentStatusBar.setText("Source: " + statusmessage);
	}
	public void setStatusBarTarget(String statusmessage){
		if (!isTabbedPaneAvailable()){
			JOptionPane.showMessageDialog(null, "Target: " + statusmessage);
			textDocumentStatusBar = new JLabel();
		}
		textDocumentStatusBar.setForeground(Color.RED);
		textDocumentStatusBar.setText("Target: " + statusmessage);
	}
	public void setStatusBar2(String statusmessage){
		textDocumentStatusBar2.setText(statusmessage);
	}
	
	public void resetStatusBar() {
		textDocumentStatusBar.setText("");
	}
	
	public boolean isTabbedPaneAvailable(){
		return this.tabbedPane.isAvailable();
	}
	public GSTabbedPane getTabbedPane(){
		return this.tabbedPane;
	}

	public void processEvent(AWTEvent e) {
		super.processEvent(e);
		// アクティブになった
		if(e.getID() == WindowEvent.WINDOW_ACTIVATED){
			// 検索ウィンドウの設定
			SearchDialogManager.setGSEditorToolBar(getGSEditorToolBar());
			if(this.tabbedPane != null){
				String key = tabbedPane.getURI();
				if(key == null){
					return;
				}
	        	GSTabbedPane newTabbedPane = GSTabbedPaneManager.getGSTabbedPane(key);
	        	if(newTabbedPane != null){
	        		String windowid = GSTabbedPaneManager.getWindowsID(key);
	        		if(windowid == null){
	        			return;
	        		}
	        		if(windowid.equals(key)){
	        			return;
	        		}
	        		newTabbedPane.save();
		        	String fstidatSource = newTabbedPane.getFirstIDATSource();
		        	this.tabbedPane.updateFirstIDAT(fstidatSource);

		        	String secondSource = newTabbedPane.getSecondIDATSource();
		        	this.tabbedPane.updateSecondIDAT(secondSource);

		        	String thirdidatSource = newTabbedPane.getThirdIDATSource();
		        	this.tabbedPane.updateThirdIDAT(thirdidatSource);

		        	
		        	this.tabbedPane.updateText();
		        	this.tabbedPane.save();
		        	GSTabbedPaneManager.removeGSTabbedPane(key);
	        	}
			}
			if(this.mode != null){
				DefaultState.getInstance().setMode(this.mode);
			}
		}else if(e.getID() == WindowEvent.WINDOW_DEACTIVATED){
			if(this.tabbedPane != null){
		       	this.tabbedPane.save();
		       	String key = tabbedPane.getURI();
	        	GSTabbedPaneManager.setGSTabbedPane(key,key,tabbedPane);
			}
		}else if(e.getID() == WindowEvent.WINDOW_CLOSED){
			if(this.tabbedPane != null){
				String key = tabbedPane.getURI();
				if(key == null){
					return;
				}			
				GSTabbedPaneManager.close(key);
			}
		}
	}

	public static boolean isFileOpened() {
		return opened;
	}

	public void setFileOpened(boolean opened) {
		WorkspaceWindow.opened = opened;
		WorkspaceWindow.makeBackupFile = true;
	}

	//2008/9/6 North Grid
	//更新フラグ
	public static boolean isUpdated() {
		return updated;
	}

	public static void setUpdated(boolean updated) {
		WorkspaceWindow.updated = updated;
		if(WorkspaceWindow.isFileOpened()) {
			WorkspaceWindow.getInstance().backup();
		}
	}

	public File getCurrentFile() {
		return currentFile;
	}

	// 2009/01/23 North Grid
	public WebDavDownLoadEvent getWebDavDownLoadEvent() {
		return webDavDownLoadEvent;
	}

	public void setWebDavDownLoadEvent(WebDavDownLoadEvent webDavDownLoadEvent) {
		this.webDavDownLoadEvent = webDavDownLoadEvent;
	}

	public int getLastsave() {
		return lastsave;
	}
	public void setLastsave(int lastsave) {
		WorkspaceWindow.lastsave = lastsave;
		if(lastsave == 1){
			this.currentFile = null;
		}
	}

	public void backup() {
		
		//2011/05/24 kukita: to cope with the error which occurs
		//when Smart-GS tries to make a backup file while the currentFile is null
		if (this.currentFile == null) {
			return;
		}
		try {
			if(makeBackupFile) {
				String backupFileName = this.currentFile.getPath() + ".bak";
				FileUtils.copyFile(this.currentFile, new File(backupFileName));
				System.out.println(backupFileName);
				makeBackupFile = false;
			}

		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	
	public ImageToolBar getImageToolBar () {
		return this.northPanel.getImageToolBar();
	}

	public HistoryToolBar getHistoryToolBar() {
		return this.northPanel.getHistoryToolBar();
	}
	
	public void setMode(Mode mode) {
		this.mode = mode;
	}
	
	public Mode getMode() {
		return this.mode;
	}

	public void updateGUI() {
		Spread spread = this.getSpread();
		if (spread != null)	this.updateGUI(spread);
	}

}
