/*
 * AnimationUtility.java
 *
 * Copyright 2012 Thomas Buck <xythobuz@me.com>
 *
 * This file is part of LED-Cube.
 *
 * LED-Cube is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * LED-Cube is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with LED-Cube.  If not, see <http://www.gnu.org/licenses/>.
 */
import java.io.FileWriter;
import java.io.File;
import java.util.Scanner;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

/**
 * A helper class that loads animations from a file or saves them to one.
 * 
 * @author Thomas Buck
 * @version 1.0
 */

public class AnimationUtility {
	private static String lastError = null;

	/**
	 * Read a file, return ArrayList with all animations in the file.
	 * 
	 * @param path Path of file
	 * @return Populated ArrayList
	 * @throws Excpetion When something goes wrong with the Scanner...
	 */
	public static Animation[] readFile(String path) throws Exception {
		Scanner sc = new Scanner(new File(path));
		Animation[] animations = new Animation[0];
		do {
			Animation tmp = readAnimation(sc);
			if (tmp == null) {
				return animations;
			}
			if (sc.hasNextLine()) {
				sc.nextLine();
			}
			animations = extendArray(animations);
			animations[animations.length - 1] = tmp;
		} while (sc.hasNextLine());

		return animations;
	}

	private static Animation[] extendArray(Animation[] animationArray) {
		Animation newArray[] = new Animation[animationArray.length + 1];
		for (int i = 0; i < animationArray.length; i++) {
			newArray[i] = animationArray[i];
		}
		return newArray;
	}

	/**
	 * Write a file with all Animations of an ArrayList
	 * 
	 * @param path Path to write to
	 * @param animations Array with all animations to be saved
	 * @see AnimationUtility#getLastError() getLastError()
	 */
	public static void writeFile(String path, Animation[] animations) {
		File f = new File(path);
		if (f.exists()) {
			try {
				f.delete();
			} catch (Exception e) {
				lastError = e.toString();
				return;
			}
		}
		FileWriter output = null;
		try {
			output = new FileWriter(f);
			for (int i = 0; i < animations.length; i++) {
				writeAnimation(animations[i], output, (i == (animations.length - 1)));
			}
		} catch (Exception e) {
			lastError = e.toString();
			return;
		} finally {
			if (output != null) {
				try {
					output.close();
				} catch (Exception e) {
					lastError = e.toString();
				}
			}
		}

	}

	/**
	 * Get the last error that occured while writing
	 * 
	 * @return Text of the exception that occured
	 */
	public static String getLastError() {
		String tmp = lastError;
		lastError = null;
		return tmp;
	}

	private static Animation readAnimation(Scanner sc) {
		Animation anim = new Animation();
		AFrame f = null;
		int index = 0;
		String tmpSize = sc.nextLine().replaceAll("\\n", "");
		if (tmpSize.equals("")) {
			return null;
		}
		Integer tmpSizeAgain = new Integer(tmpSize);
		int size = tmpSizeAgain.intValue();
		anim.setName(sc.nextLine());
		while (size > 0) {
			f = readFrame(sc, index);
			anim.setFrame(f, index);
			index++;
			size--;
		}
		return anim;
	}

	private static AFrame readFrame(Scanner sc, int index) {
		AFrame frame = new AFrame();
		frame.setName(sc.nextLine());
		short[] d = {};
		for (int i = 0; i < 8; i++) {
			short[] data = hexConvert(sc.nextLine());
			d = concat(d, data);
		}

		frame.setData(d);
		d = hexConvert(sc.nextLine());
		frame.setTime(d[0]);
		return frame;
	}

	private static short[] concat(short[] a, short[] b) {
		short[] c = new short[a.length + b.length];
		System.arraycopy(a, 0, c, 0, a.length);
		System.arraycopy(b, 0, c, a.length, b.length);
		return c;
	}

	private static short[] hexConvert(String hex) {
		hex = hex.replaceAll("\\n", "");

		short[] tmp = new short[hex.length() / 2];
		for (int i = 0; i < hex.length(); i = i + 2) {
			char[] tmpString = new char[2];
			tmpString[0] = hex.charAt(i);
			tmpString[1] = hex.charAt(i + 1);
			String tmpS = String.copyValueOf(tmpString);
			if (i == 0) {
				tmp[0] = Short.parseShort(tmpS, 16);
			} else {
				tmp[i / 2] = Short.parseShort(tmpS, 16);
			}

		}
		return tmp;

	}

	private static void writeAnimation(Animation anim, FileWriter f,
			boolean last) throws IOException {
		f.write(anim.size() + "\n");
		f.write(anim.getName() + "\n");
		for (int i = 0; i < anim.size(); i++) {
			writeFrame(anim.getFrame(i), f);
		}
		if (!last) {
			f.write("\n");
		}
	}

	private static void writeFrame(AFrame fr, FileWriter f) throws IOException {
		f.write(fr.getName() + "\n");
		for (int i = 0; i < 8; i++) {
			writeLayer(fr.getLayer(i), f);
		}
		f.write(Integer.toString((fr.getTime() & 0xff) + 0x100, 16)
				.substring(1) + "\n");
	}

	private static void writeLayer(short[] l, FileWriter f) throws IOException {
		String hex = "";
		for (int i = 0; i < l.length; i++) {
			hex += Integer.toString((l[i] & 0xff) + 0x100, 16).substring(1);
		}
		hex += "\n";

		f.write(hex);
	}
}