package electrosphere.renderer.anim;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.PriorityQueue;
import org.joml.Quaternionf;
import org.joml.Vector3f;
import org.lwjgl.PointerBuffer;
import org.lwjgl.assimp.AIAnimation;
import org.lwjgl.assimp.AIMeshAnim;
import org.lwjgl.assimp.AIMeshKey;
import org.lwjgl.assimp.AINodeAnim;
import org.lwjgl.assimp.AIQuatKey;
import org.lwjgl.assimp.AIVectorKey;

/**
 *
 * @author satellite
 */
public class Animation {
    
    public static final String ANIMATION_MOVEMENT_STARTUP = "Armature|WalkStart";
    public static final String ANIMATION_MOVEMENT_MOVE = "Armature|Walk";
    public static final String ANIMATION_IDLE_1 = "Armature|Idle1";
    public static final String ANIMATION_SWING_PRIMARY = "Armature|SwingWeapon";
    
    
    
    AIAnimation animData;
    public String name;
    public int ID;
    ArrayList<AINodeAnim> nodeChannelData;
    ArrayList<AIMeshAnim> meshChannelData;
    public ArrayList<AnimChannel> channels;
    public double duration = 0;
    public double timeCurrent = 0;
    public double ticksPerSecond;
    public Animation(AIAnimation animData, int ID){
        //
        //Read in metadata
        //
        this.animData = animData;
        name = animData.mName().dataString();
        this.duration = animData.mDuration();
        this.ticksPerSecond = animData.mTicksPerSecond();
        this.ID = ID;
        //
        //Print metadata
        //
//        System.out.println("Animation name: \"" + name + "\"");
//        System.out.println("ID:(" + ID + ")");
//        System.out.println("Ticks per second: " + ticksPerSecond);
//        System.out.println("Anim sizeof: " + animData.sizeof());
//        System.out.println("Duration: " + duration);
        //
        //Read in anim channels (bone modifications)
        //
        int channelCount = animData.mNumChannels();
        channels = new ArrayList();
        if(channelCount > 0){
//            System.out.println("Channel count: " + channelCount);
            for(int i = 0; i < channelCount; i++){
                AINodeAnim currentChannelData = AINodeAnim.create(animData.mChannels().get(i));
//                System.out.println("Channel[" + (i + 1) + "]: " + currentChannelData.mNodeName().dataString());
                
                //Create channel
                AnimChannel currentChannel = new AnimChannel(duration);
                currentChannel.positionFrame = new ArrayList();
                currentChannel.rotationFrame = new ArrayList();
                currentChannel.scaleFrame = new ArrayList();
                currentChannel.nodeID = currentChannelData.mNodeName().dataString();
                channels.add(currentChannel);
                
                
                //get channel data
                
                if(currentChannelData.mNumPositionKeys() > 0){
                    org.lwjgl.assimp.AIVectorKey.Buffer buff = currentChannelData.mPositionKeys();
//                    Iterator<AIVectorKey> keyIterator = buff.iterator();
//                    while (keyIterator.hasNext()) {
//                        AIVectorKey key = keyIterator.next();
//                        Keyframe currentFrame = new Keyframe(key.mTime());
//                        currentFrame.position = new Vector3f(key.mValue().x(), key.mValue().y(), key.mValue().z());
//                        currentChannel.positionFrame.add(currentFrame);
//                    }
                    if(buff != null && buff.hasRemaining()){
//                        System.out.println("Position vectors: ");
                        AIVectorKey key = buff.get();
                        Keyframe currentFrame = new Keyframe(key.mTime());
                        currentFrame.position = new Vector3f(key.mValue().x(), key.mValue().y(), key.mValue().z());
                        currentChannel.positionFrame.add(currentFrame);
//                        System.out.println(currentFrame.position);
                        currentChannel.startingPosition = currentFrame.position;
                        
                        Keyframe previousFrame;
                        while(buff.hasRemaining()){
                            previousFrame = currentFrame;
                            key = buff.get();
                            currentFrame = new Keyframe(key.mTime());
                            currentFrame.position = new Vector3f(key.mValue().x(), key.mValue().y(), key.mValue().z());
//                            System.out.println(currentFrame.position);
                            //check if duplicate
//                            Keyframe previousFrame = currentChannel.positionFrame.get(currentChannel.positionFrame.size() - 1);
                            if(     previousFrame.position.x == currentFrame.position.x &&
                                    previousFrame.position.y == currentFrame.position.y &&
                                    previousFrame.position.z == currentFrame.position.z
                                    ){
                            } else {
                                currentChannel.positionFrame.add(currentFrame);
                            }
                        }
                    }
                }
                
                if(currentChannelData.mNumRotationKeys() > 0){
                    org.lwjgl.assimp.AIQuatKey.Buffer buff = currentChannelData.mRotationKeys();
                    if(buff != null && buff.hasRemaining()){
                        AIQuatKey key = buff.get();
                        Keyframe currentFrame = new Keyframe(key.mTime());
                        currentFrame.rotation = new Quaternionf();
                        currentFrame.rotation.set(key.mValue().x(), key.mValue().y(), key.mValue().z(), key.mValue().w());
//                        currentFrame.rotation = new Quaternionf(key.mValue().x(),key.mValue().y(),key.mValue().z(),key.mValue().w());
                        currentChannel.rotationFrame.add(currentFrame);
                        
                        currentChannel.startingRotation = currentFrame.rotation;
                        
                        Keyframe previousFrame;
                        while(buff.hasRemaining()){
                            previousFrame = currentFrame;
                            key = buff.get();
                            currentFrame = new Keyframe(key.mTime());
                            currentFrame.rotation = new Quaternionf();
                            currentFrame.rotation.set(key.mValue().x(), key.mValue().y(), key.mValue().z(), key.mValue().w());
//                            currentFrame.rotation = new Quaternionf(key.mValue().x(),key.mValue().y(),key.mValue().z(),key.mValue().w());
                            //check for duplicate
//                            Keyframe previousFrame = currentChannel.rotationFrame.get(currentChannel.rotationFrame.size() - 1);
                            if(     previousFrame.rotation.w == currentFrame.rotation.w &&
                                    previousFrame.rotation.x == currentFrame.rotation.x &&
                                    previousFrame.rotation.y == currentFrame.rotation.y &&
                                    previousFrame.rotation.z == currentFrame.rotation.z
                                    ){
                            } else {
                                currentChannel.rotationFrame.add(currentFrame);
                            }
                        }
                    }
//                    Iterator<AIQuatKey> keyIterator = buff.iterator();
//                    while(keyIterator.hasNext()){
//                        AIQuatKey key = keyIterator.next();
//                        Keyframe currentFrame = new Keyframe(key.mTime());
//                        currentFrame.rotation = new Quaternionf(key.mValue().w(),key.mValue().x(),key.mValue().y(),key.mValue().z());
//                        currentChannel.rotationFrame.add(currentFrame);
//                    }
                }
                
                if(currentChannelData.mNumScalingKeys() > 0){
                    org.lwjgl.assimp.AIVectorKey.Buffer buff = currentChannelData.mScalingKeys();
//                    Iterator<AIVectorKey> keyIterator = buff.iterator();
//                    while (keyIterator.hasNext()) {
//                        AIVectorKey key = keyIterator.next();
//                        Keyframe currentFrame = new Keyframe(key.mTime());
//                        currentFrame.scale = new Vector3f(key.mValue().x(), key.mValue().y(), key.mValue().z());
//                        currentChannel.scaleFrame.add(currentFrame);
//                    }
                    if(buff != null && buff.hasRemaining()){
                        AIVectorKey key = buff.get();
                        Keyframe currentFrame = new Keyframe(key.mTime());
                        currentFrame.scale = new Vector3f(key.mValue().x(), key.mValue().y(), key.mValue().z());
                        currentChannel.scaleFrame.add(currentFrame);
                        Keyframe previousFrame;
                        while(buff.hasRemaining()){
                            previousFrame = currentFrame;
                            key = buff.get();
                            currentFrame = new Keyframe(key.mTime());
                            currentFrame.scale = new Vector3f(key.mValue().x(), key.mValue().y(), key.mValue().z());
                            if(     currentFrame.scale.x == previousFrame.scale.x &&
                                    currentFrame.scale.y == previousFrame.scale.y &&
                                    currentFrame.scale.z == previousFrame.scale.z
                                    ){
                            } else {
                                currentChannel.scaleFrame.add(currentFrame);
                            }
                        }
                    }
                }
                
                
//                System.out.println("end times");
//                for(int j = 0; j < currentChannelData.mNumPositionKeys(); j++){
//                    org.lwjgl.assimp.AIVectorKey.Buffer buff = currentChannelData.mPositionKeys();
//                    Iterator<AIVectorKey> keyIterator = buff.iterator();
//                    AIVectorKey posKey = currentChannelData.mPositionKeys().get(i);
//                    Keyframe currentFrame = new Keyframe(posKey.mTime());
//                    currentFrame.position = new Vector3f(posKey.mValue().x(),posKey.mValue().y(),posKey.mValue().z());
//                }
//                for(int j = 0; j < currentChannelData.mNumRotationKeys(); j++){
//                    AIQuatKey rotKey = currentChannelData.mRotationKeys().get(i);
//                    HashMap test = new HashMap();
//                    System.out.println(new Quaternionf(rotKey.mValue().w(),rotKey.mValue().x(),rotKey.mValue().y(),rotKey.mValue().z()));
//                }
//                for(int j = 0; j < currentChannelData.mNumScalingKeys(); j++){
//                    AIVectorKey scaleKey = currentChannelData.mScalingKeys().get(i);
////                    scaleKey.mValue().
//                    System.out.println(new Vector3f(scaleKey.mValue().x(),scaleKey.mValue().y(),scaleKey.mValue().z()));
//                }
            }
        }
//        int meshChannelCount = animData.mNumMeshChannels();
//        meshChannelData = new ArrayList();
//        if(meshChannelCount > 0){
//            for(int i = 0; i < meshChannelCount; i++){
//                AIMeshAnim test = AIMeshAnim.create(animData.mMeshChannels().get(i));
//            }
//        }
        //gotta free things
        nodeChannelData = null;
        meshChannelData = null;
    }
    public void describeAnimation(){
        System.out.println("=====================");
        System.out.println("Name: \"" + name + "\"");
        System.out.println("ID: " + ID);
        System.out.println("Duration: " + duration);
        System.out.println("Ticks per second: " + ticksPerSecond);
        Iterator<AnimChannel> channelIterator = channels.iterator();
        while(channelIterator.hasNext()){
            AnimChannel channelCurrent = channelIterator.next();
            System.out.println("=====================");
            channelCurrent.describeChannel();
        }
        System.out.println("=====================");
    }
    public void fullDescribeAnimation(){
        System.out.println("=====================");
        System.out.println("Name: " + name);
        System.out.println("ID: " + ID);
        System.out.println("Duration: " + duration);
        System.out.println("Ticks per second: " + ticksPerSecond);
        Iterator<AnimChannel> channelIterator = channels.iterator();
        while(channelIterator.hasNext()){
            AnimChannel channelCurrent = channelIterator.next();
            System.out.println("=====================");
            channelCurrent.fullDescribeChannel();
        }
        System.out.println("=====================");
    }
    
    public boolean incrementTime(double time){
        timeCurrent += time;
        if(timeCurrent > duration){
            return true;
        } else {
            return false;
        }
    }
    
    public void setTime(double time){
        timeCurrent = time;
    }
}
