/*******************************************************************************
* Copyright (c)                                                                *
*           2005   Tristan Allwood,                                            *
*           2005   Daniel Burke,                                               *
*           2005   Marc Hull,                                                  *
*           2005   Ekaterina Itskova,                                          *
*           2005   Steve Zymler                                                *
*                                                                              *
* Permission is hereby granted, free of charge, to any person obtaining a      *
* copy of this software and associated documentation files (the                *
* "Software"), to deal in the Software without restriction, including          *
* without limitation the rights to use, copy, modify, merge, publish,          *
* distribute, sublicense, and/or sell copies of the Software, and to           *
* permit persons to whom the Software is furnished to do so, subject to        *
* the following conditions:                                                    *
*                                                                              *
* The above copyright notice and this permission notice shall be included      *
* in all copies or substantial portions of the Software.                       *
*                                                                              *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS      *
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF                   *
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.       *
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY         *
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,         *
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE            *
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                       *
*******************************************************************************/
/*
 * Created on 22-Dec-2004
 *
 */
package uk.ac.ic.doc.kevlar.gui.internal.taskpane.savepane;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.util.ArrayList;
import java.util.List;

import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.ImageData;
import org.eclipse.swt.graphics.ImageLoader;

import uk.ac.ic.doc.kevlar.gui.GUIManager;
import uk.ac.ic.doc.kevlar.gui.internal.ADrawableObject;
import uk.ac.ic.doc.kevlar.gui.internal.caches.Converter;
import uk.ac.ic.doc.kevlar.gui.internal.pipeline.Macro;
import uk.ac.ic.doc.kevlar.gui.internal.pipeline.PipeLineManager;
import uk.ac.ic.doc.kevlar.gui.internal.pipeline.Program;
import uk.ac.ic.doc.kevlar.hial.IGUIContextSaver;
import uk.ac.ic.doc.kevlar.hial.IRefObject;
import uk.ac.ic.doc.kevlar.publicUtil.dom.XMLUtil;

/**
 * @author Kate
 *
 */
public class GUISaverCallback implements IGUIContextSaver{

	private static GUISaverCallback singleton;
	int macroID;
	int innerID;
	
	public static void createSingleton()
	{
		if (singleton==null)
		{
			singleton = new GUISaverCallback();
		}
	}
	
	public static GUISaverCallback getSingleton()
	{
		return singleton;
	}
	
	/* (non-Javadoc)
	 * @see uk.ac.ic.doc.kevlar.hial.IGUIContextSaver#putGUIContext(java.lang.StringBuilder, int)
	 */
	public void putGUIContext(StringBuilder text, int depth) {
		/* put image data into a file */
	
		//create a image of the current pipeline
		Image image = PipeLineManager.getSingleton().createSnapshot();
		
		//convert image data into hex string
		ByteArrayOutputStream bos = new ByteArrayOutputStream();
		
		ImageLoader imageLoader = new ImageLoader();
		imageLoader.data = new ImageData[] {image.getImageData()};
		imageLoader.save(bos, SWT.IMAGE_JPEG);
	        
		String imageData = Converter.convertToString(bos.toByteArray());
		
		//write into file between tags <thumb></thumb>
		XMLUtil.putElement(text, "thumb", imageData, depth);
		
		
		/* write out gui data for macros */	
		putMacro(text, depth);
	}

	/* (non-Javadoc)
	 * @see uk.ac.ic.doc.kevlar.hial.IGUIContextSaver#putGUIPipe(java.lang.StringBuilder, uk.ac.ic.doc.kevlar.hial.IRefObject, int)
	 */
	public void putGUIPipe(StringBuilder text, IRefObject pipeRef, int depth) {
		/* doesn't need to be implemented, since no specific 
		 * gui data is required to be stored for a pipe
		 */
		
		XMLUtil.putElement(text, "guipipe", " ", depth);
	}

	/* (non-Javadoc)
	 * @see uk.ac.ic.doc.kevlar.hial.IGUIContextSaver#putGUIProgram(java.lang.StringBuilder, uk.ac.ic.doc.kevlar.hial.IRefObject, int)
	 */
	public void putGUIProgram(StringBuilder text, IRefObject programRef, int depth) {
		//put layout data for the program
		
		XMLUtil.putElement(text, "refId", programRef.toString(), depth);
		
		depth = XMLUtil.putOpenElem(text, "layout", depth);
		
		
		
		int xpos = ((Program)programRef).getAlignedArea().x;
		int ypos = ((Program)programRef).getAlignedArea().y;
		int width = ((Program)programRef).getAlignedArea().width;
		int height = ((Program)programRef).getAlignedArea().height;
		
		XMLUtil.putElement(text, "xposition", Integer.toString(xpos), depth);
		XMLUtil.putElement(text, "yposition", Integer.toString(ypos), depth);
		XMLUtil.putElement(text, "width", Integer.toString(width), depth);
		XMLUtil.putElement(text, "height", Integer.toString(height), depth);
		
		depth = XMLUtil.putCloseElem(text, "layout", depth);
		
	}
	
	private void putMacro(StringBuilder text, int depth)
	{
		macroID = 0;
		
		List<ADrawableObject> pipeLineContent = PipeLineManager.getSingleton().getContents().getChildren();
		
		if (!pipeLineContent.isEmpty())
		{
			depth = XMLUtil.putOpenElem(text, "macros", depth);
		
			for (ADrawableObject child : pipeLineContent)
			{
				if (child instanceof Macro)
				{
					//depth = XMLUtil.putOpenElem(text, "macro", depth);
					
					List macroPrograms = ((Macro)child).getPrograms();
					innerID = macroID+1;
					List<Macro> innerMacros = saveMacro(text, depth, macroPrograms, (Macro)child);
				
					for (int i = 0; i<innerMacros.size(); i++)
					{
						Macro m = innerMacros.get(i);
						macroID++;
						innerMacros.addAll(saveMacro(text, depth, m.getPrograms(), m));
					}
					
				
					macroID = innerID;
				}
				
				
			}
			
			depth = XMLUtil.putCloseElem(text, "macros", depth);
		}
		else
		{
			XMLUtil.putElement(text, "macros", " ", depth);
		}
		
	}
	
	private List saveMacro(StringBuilder text, int depth, List macroContents, Macro parent)
	{
	
		List innerMacros = new ArrayList();
		
		depth = XMLUtil.putOpenElem(text, "macro", depth);
		
		XMLUtil.putElement(text, "macroId", Integer.toString(macroID), depth);
		
		depth = XMLUtil.putOpenElem(text, "layout", depth);
		
		int xpos = parent.getAlignedArea().x;
		int ypos = parent.getAlignedArea().y;
		int width = parent.getAlignedArea().width;
		int height = parent.getAlignedArea().height;
		
		XMLUtil.putElement(text, "xposition", Integer.toString(xpos), depth);
		XMLUtil.putElement(text, "yposition", Integer.toString(ypos), depth);
		
		System.out.println("MacroID: "+macroID+" ypos: "+ypos);
		XMLUtil.putElement(text, "width", Integer.toString(width), depth);
		XMLUtil.putElement(text, "height", Integer.toString(height), depth);
		
		depth = XMLUtil.putCloseElem(text, "layout", depth);
		
		
		for (int i = 0; i<macroContents.size(); i++)
		{
			IRefObject macroElement = (IRefObject)macroContents.get(i);
			
			if (macroElement instanceof Macro)
			{
				innerMacros.add(macroElement);
			}
			else if (macroElement instanceof Program)
			{
				XMLUtil.putElement(text, "macro-program", macroElement.toString(), depth);
			}
		}
		
		if (innerMacros.isEmpty())
		{
			XMLUtil.putElement(text, "innerMacroId", Integer.toString(-1), depth);
			System.out.println(Integer.toString(-1));
		}
		for (int i = 0; i<innerMacros.size(); i++)
		{
			XMLUtil.putElement(text, "innerMacroId", Integer.toString(innerID++), depth);
		}
		
		depth = XMLUtil.putCloseElem(text, "macro", depth);
		
		return innerMacros;
	}

}
