package com.l2client.util;

import java.io.IOException;
import java.util.Collection;
import java.util.HashMap;
import java.util.WeakHashMap;
import java.util.logging.Logger;

import com.jme3.animation.AnimControl;
import com.jme3.animation.AnimationProvider;
import com.jme3.animation.BoneAnimation;
import com.jme3.export.JmeExporter;
import com.jme3.export.JmeImporter;
import com.l2client.asset.AssetManager;
import com.l2client.model.PartSet;


public final class AnimationManager {
	
	private HashMap<String, HashMap<String, PartSet>> animationParts = new HashMap<String, HashMap<String,PartSet>>();
	private static HashMap<String,PartSet> noAnims = new HashMap<String,PartSet>();

	class PartSetAnimationProvider extends AnimationProvider {
		HashMap<String,PartSet> anims = null;
		
		PartSetAnimationProvider(){
		}
		/**
		 * do nothing, animations are configured in the partset control
		 */
		@Override
		public void setAnimations(HashMap<String, BoneAnimation> animations) {
			//left empty by purpose
		}

		@Override
		public BoneAnimation getAnimation(String name, AnimControl control) {
			//FIXME correct this in the loader!!
			PartSet p = anims.get(name.toLowerCase());
			if(p != null){
			BoneAnimation anim = AnimationManager.get().getAnimation(p.getNext());
			if(anim != null)
				anim.rewireBoneTracks(control.getSkeleton());
			return anim;
			}
			return null;
		}

		@Override
		public void removeAnimation(String name) {
			//do nothing
		}

		@Override
		public void addAnimation(BoneAnimation anim) {
			//do nothing
		}

		@Override
		public Collection<String> getAnimationNames() {
			// TODO Auto-generated method stub
			return null;
		}

		@Override
		public void write(JmeExporter ex) throws IOException {
			//do nothing
		}

		@Override
		public void read(JmeImporter im) throws IOException {
			//do nothing
		}
		@Override
		public float getAnimationLength(String name) {
			// TODO Auto-generated method stub
			return 0;
		}

	}

	
	private static Logger logger = Logger.getLogger(AnimationManager.class.getName());
	
	public static String MANDATORY = "F";
	private static AnimationManager singleton = null;	
	private static WeakHashMap<String, BoneAnimation> loadedAnimations = new WeakHashMap<String, BoneAnimation>(); 
	private static PartSetAnimationProvider noAnimationsProvider = null;

	public final AnimationProvider getAnimationProvider(String animParts) {
		HashMap<String, PartSet> ret = animationParts.get(animParts);
		
		if(ret != null){
			PartSetAnimationProvider a = new PartSetAnimationProvider();
			a.anims = ret;
			return a;
		}
		else {
			return noAnimationsProvider;
		}
	}

	/**
	 * singleton private constructor
	 */
	private AnimationManager() {
		singleton = this;
		noAnimationsProvider = new PartSetAnimationProvider();
		noAnimationsProvider.anims = (noAnims);
		logger.info("Singleton initialized");
	}

	/**
	 * Fetch the singleton instance (created in case not done so far)
	 * 
	 * @return The instance
	 */
	public static AnimationManager get() {
		if (singleton != null)
			return singleton;
		else {
			return new AnimationManager();
		}
	}
//	//NOT USED atm
//	public void precacheAnimations(PartSet set){
//		for(PartSet e: set.getParts()){	
//			loadAnimation(e.getName(), e.getName(),false);
//		}
//	}
	
	private BoneAnimation loadAnimation(String path, boolean direct){
		logger.info("Loading "+path);
//		Asset a = null;
//		synchronized (loadedAnimations) {
//			a = loadedAnimations.get(path); 
//			if (a != null) {
//				logger.info("Found "+path);
//				return a;
//			} else {
//				a = new Asset(path, path);
//				loadedAnimations.put(path, a);
//				AssetManager.getInstance().loadAsset(a, direct);
//				
//				logger.info("Loaded "+path);
//				return a;
//			}	
//		}
		BoneAnimation a = (BoneAnimation) AssetManager.getInstance().getJmeAssetMan().loadAsset(path);
		return a;
	}
	
	//FIXME storage of named animations should be refactored, to many string around here
	//FIXME animsystem uses future itself, so no need to load directly 
	public BoneAnimation getAnimation(String path){
		BoneAnimation a ;
		//FIXME remove this !=!
		if(path.endsWith(".j3o"))
			a = loadAnimation(path, true);
		else
			a = loadAnimation(path+".j3o", true);	
		return (BoneAnimation)a;
	}

	public HashMap<String, PartSet> precacheAnimations(PartSet det) {
		HashMap<String, PartSet> set = animationParts.get(det.getName()) ;
		if(set != null) {
			logger.severe("someone wants to recaches animparts for:"+det.getName());
			return set;
		}
			
		set = new HashMap<String, PartSet>();
		for(PartSet e : det.getParts()){
			set.put(e.getName(), e);
		}
		
		if(set.size() > 0){
			animationParts.put(det.getName(), set);
			return set;
		}
		else 
			return noAnims;
	}
}
