
/**
 * Copyright 2008 - 2011
 * 
 * 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.
 * 
 * @project loon
 * @author cping
 * @email：javachenpeng@yahoo.com
 * @version 0.1
 */
package loon.action.sprite;

import java.util.ArrayList;

import loon.LSystem;
import loon.core.LRelease;
import loon.core.event.Updateable;
import loon.core.graphics.device.LColor;
import loon.core.graphics.opengl.LTexture;
import loon.core.graphics.opengl.LTextures;
import loon.core.graphics.opengl.TextureUtils;
import loon.utils.CollectionUtils;

public class Animation implements LRelease {

	public interface AnimationListener {
		public void onComplete(Animation animation);
	}

	public AnimationListener Listener;

	public void setAnimationListener(AnimationListener l) {
		this.Listener = l;
	}

	public AnimationListener getAnimationListener() {
		return this.Listener;
	}

	boolean isRunning;

	private ArrayList<AnimationFrame> frames;

	int loopCount, loopPlay;

	int currentFrameIndex;

	long animTime, totalDuration;

	int size;

	public Animation() {
		this(new ArrayList<AnimationFrame>(CollectionUtils.INITIAL_CAPACITY), 0);
	}

	public Animation(Animation a) {
		this.isRunning = a.isRunning;
		this.frames = new ArrayList<Animation.AnimationFrame>(a.frames);
		this.loopCount = a.loopCount;
		this.loopPlay = a.loopPlay;
		this.currentFrameIndex = a.currentFrameIndex;
		this.animTime = a.animTime;
		this.totalDuration = a.totalDuration;
		this.size = frames.size();
	}

	private Animation(ArrayList<AnimationFrame> frames, long totalDuration) {
		this.loopCount = -1;
		this.frames = frames;
		this.size = frames.size();
		this.totalDuration = totalDuration;
		this.isRunning = true;
		start();
	}

	public static Animation getDefaultAnimation(String fileName) {
		return Animation.getDefaultAnimation(LTextures.loadTexture(fileName));
	}

	public static Animation getDefaultAnimation(final LTexture texture) {
		return Animation.getDefaultAnimation(new LTexture[] { texture }, 1,
				65535);
	}

	/**
	 * 转化指定文件为动画图像
	 * 
	 * @param fileName
	 * @param width
	 * @param height
	 * @param timer
	 * @return
	 */
	public static Animation getDefaultAnimation(String fileName, int width,
			int height, int timer) {
		return Animation.getDefaultAnimation(
				TextureUtils.getSplitTextures(fileName, width, height), -1,
				timer);
	}

	/**
	 * 转化指定文件为动画图像
	 * 
	 * @param fileName
	 * @param width
	 * @param height
	 * @param timer
	 * @param filterColor
	 * @return
	 */
	public static Animation getDefaultAnimation(String fileName, int width,
			int height, int timer, LColor filterColor) {
		return Animation.getDefaultAnimation(
				TextureUtils.getSplitTextures(
						TextureUtils.filterColor(fileName, filterColor), width,
						height), -1, timer);
	}

	/**
	 * 转化指定文件为动画图像
	 * 
	 * @param fileName
	 * @param maxFrame
	 * @param width
	 * @param height
	 * @param timer
	 * @return
	 */
	public static Animation getDefaultAnimation(String fileName, int maxFrame,
			int width, int height, int timer) {
		return Animation.getDefaultAnimation(
				TextureUtils.getSplitTextures(fileName, width, height),
				maxFrame, timer);
	}

	/**
	 * 转化一组Image为动画图像
	 * 
	 * @param images
	 * @param maxFrame
	 * @param width
	 * @param height
	 * @param timer
	 * @return
	 */
	public static Animation getDefaultAnimation(LTexture[] images,
			int maxFrame, int timer) {
		if (images == null) {
			return new Animation();
		}
		Animation animation = new Animation();
		if (maxFrame != -1) {
			for (int i = 0; i < maxFrame; i++) {
				animation.addFrame(images[i], timer);
			}
		} else {
			int size = images.length;
			for (int i = 0; i < size; i++) {
				animation.addFrame(images[i], timer);
			}
		}
		return animation;
	}

	/**
	 * 克隆一个独立动画
	 */
	@Override
	public Object clone() {
		return new Animation(frames, totalDuration);
	}

	/**
	 * 添加一个动画图像
	 * 
	 * @param image
	 * @param timer
	 */
	public synchronized void addFrame(LTexture image, long timer) {
		totalDuration += timer;
		frames.add(new AnimationFrame(image, totalDuration));
		size++;
	}

	/**
	 * 添加一个动画图像
	 * 
	 * @param fileName
	 * @param timer
	 */
	public synchronized void addFrame(String fileName, long timer) {
		addFrame(LTextures.loadTexture(fileName), timer);
	}

	/**
	 * 开始执行动画
	 * 
	 */
	public synchronized void start() {
		animTime = 0;
		if (size > 0) {
			currentFrameIndex = 0;
		}
	}

	/**
	 * 刷新动画为初始状态
	 */
	public void reset() {
		animTime = 0;
		currentFrameIndex = 0;
		loopPlay = 0;
		loopCount = -1;
		isRunning = true;
	}

	/**
	 * 更新当前动画
	 * 
	 * @param timer
	 */
	public synchronized void update(long timer) {
		if (loopCount != -1 && loopPlay > loopCount) {
			return;
		}
		if (isRunning) {
			if (size > 0) {
				animTime += timer;
				if (animTime > totalDuration) {
					if (Listener != null) {
						Listener.onComplete(this);
					}
					animTime = animTime % totalDuration;
					currentFrameIndex = 0;
					loopPlay++;
				}
				for (; animTime > getFrame(currentFrameIndex).endTimer;) {
					currentFrameIndex++;
				}
			}
		}
	}

	/**
	 * 返回当前动画图象
	 * 
	 * @return
	 */
	public LTexture getSpriteImage() {
		if (size == 0) {
			return null;
		} else {
			final LTexture texture = getFrame(currentFrameIndex).image;
			if (!texture.isLoaded()) {
				Updateable update = new Updateable() {
					@Override
					public void action(Object a) {
						texture.loadTexture();
					}
				};
				LSystem.load(update);
			}
			return texture;
		}
	}

	/**
	 * 返回当前动画图象
	 * 
	 * @param index
	 * @return
	 */
	public LTexture getSpriteImage(int index) {
		if (index < 0 || index >= size) {
			return null;
		} else {
			LTexture texture = getFrame(index).image;
			if (!texture.isLoaded()) {
				texture.loadTexture();
			}
			return texture;
		}
	}

	/**
	 * 返回当前动画面板
	 * 
	 * @param i
	 * @return
	 */
	private AnimationFrame getFrame(int index) {
		if (index < 0) {
			return frames.get(0);
		} else if (index >= size) {
			return frames.get(size - 1);
		}
		return frames.get(index);
	}

	/**
	 * 设定停止状态
	 * 
	 * @param isStop
	 */
	public void setRunning(boolean runing) {
		this.isRunning = runing;
	}

	/**
	 * 返回动画状态
	 * 
	 * @param isStop
	 */
	public boolean isRunning() {
		return this.isRunning;
	}

	/**
	 * 返回当前动画索引
	 * 
	 * @return
	 */
	public int getCurrentFrameIndex() {
		return this.currentFrameIndex;
	}

	public void setCurrentFrameIndex(int index) {
		this.currentFrameIndex = index;
	}

	public int getTotalFrames() {
		return size;
	}

	public int getLoopCount() {
		return loopCount;
	}

	public void setLoopCount(int loopCount) {
		this.loopCount = loopCount;
	}

	private class AnimationFrame implements LRelease {

		LTexture image;

		long endTimer;

		public AnimationFrame(LTexture image, long endTimer) {
			this.image = image;
			this.endTimer = endTimer;
		}

		@Override
		public void dispose() {
			if (image != null) {
				LTexture father = image.getParent();
				if (father != null && !father.isClose()) {
					father.destroy();
				} else if (image != null && !image.isClose()) {
					image.destroy();
				}
			}
		}
	}

	@Override
	public void dispose() {
		if (frames != null) {
			for (AnimationFrame frame : frames) {
				if (frame != null) {
					frame.dispose();
					frame = null;
				}
			}
			frames.clear();
		}
		this.size = 0;
	}

}
