using System;
using System.IO;
using System.Collections.Generic;

using Animrig;
using CommonMemoryStream;

namespace sample_testunit
{
    class Program
    {
        // log callback
        static void LogCallback(string s)
        {
            Console.WriteLine(s);
        }
        // event callback
        static void EvenetCallback(AnimationrigState stste, ref StateEventData data)
        {
            char d = '\"';
            Logger.Log("event");
            Logger.Log("  name : " + data.ID);
            Logger.Log("  strings : " + d+data.Strings0+d + " , " + d+data.Strings1+d);
            Logger.Log("  floats : " + Logger.FloatToStr(data.Floats0) + " , " + Logger.FloatToStr(data.Floats1));
        }
        // object log
        static void ObjectLogOut(AnimObject o)
        {
            Logger.Log("object.state");
            Logger.Log("  name : " + o.Name);
            Logger.Log("  enable : " + Logger.BoolToStr(o.Enable));
            Logger.Log("  visible : " + Logger.BoolToStr(o.Visible));
            Logger.Log("  offset : " + Logger.VectorToStr(ref o.Offset));
            Logger.Log("  scale : " + Logger.VectorToStr(ref o.Scale));
            Logger.Log("  parent object index : " + Logger.IntToStr(o.ParentObjectIndex));
            Logger.Log("  draw priority : " + Logger.FloatToStr(o.DrawPriority));
        }
        // track log
        static void TrackLogOut(StateTrack o, int index, string name)
        {
            Logger.Log(name + ".statetrack[" + Logger.IntToStr(index) + "]");
            if (o == null)
            {
                Logger.Log("  null");
                return;
            }

            Logger.Log("  enable : " + Logger.BoolToStr(o.Enable));
            Logger.Log("  play frame : " + Logger.FloatToStr((float)o.PlayFrame));
            Logger.Log("  track alpha : " + Logger.FloatToStr(o.TrackAlphaEase.Value));
            Logger.Log("  mix alpha : " + Logger.FloatToStr(o.MixAlphaEase.Value));
        }
        // test
        static bool process()
        {
            // log callback
            Logger.OnLog = LogCallback;
            // setup data
            var anim = new Animationrig();
            // load
            {
                MemoryStream ms = CommonMS.LoadFromFile("data/sample.animrig");
                if (ms == null)
                {
                    Console.WriteLine("file error : sample.animrig");
                    return false;
                }

                if (!anim.LoadFromBinary(ms))
                {
                    Console.WriteLine("load error : AnimationRig : " + anim.LastError);
                    return false;
                }
            }

            // setup state
            var state = new AnimationrigState(anim);
            state.OnEvent = EvenetCallback;

            // setup preset
            var preset = new Preset();
            {
                MemoryStream ms = CommonMS.LoadFromFile("data/sample.animrig.preset.txt");
                if (ms == null)
                {
                    Console.WriteLine("file error : sample.animrig.preset.txt");
                    return false;
                }
                if (!preset.LoadFromStream(ms))
                {
                    Console.WriteLine("load error : preset");
                    return false;
                }
            }

            // setup logger
            var logger = new StateLogRenderer(ObjectType.Spine);
            logger.name = "logger";
            state.Inputs[0].Renderer = logger;

            // object log
            ObjectLogOut(anim.Objects[0]);

            // update
            {
                var interval = 60;
                for (var i = 0; i < interval; i++) Update(state);

                state.EntryTrack(0, "setup");
                state.EntryTrack(1, "test");
                preset.SetDefault(state.Inputs[0]);
                for (var i = 0; i < interval; i++) Update(state);

                preset.SetPreset(state.Inputs[0], "lookdown", 1.0f);
                for (var i = 0; i < interval; i++) Update(state);

                state.EntryTrackFade(2, "lol", 1.0f);
                for (var i = 0; i < interval; i++) Update(state);

                state.EntryTrackFade(2, "boo", 1.0f);
                var ms = new MemoryStream();
                state.SaveToBinary(ms);
                Console.WriteLine($"state save to binary : {ms.Length}KB");
                for (var i = 0; i < interval; i++) Update(state);

                state.ClearTrackFade(2, 1.0f);
                preset.SetClear(state.Inputs[0], 1.0f);
                for (var i = 0; i < interval; i++) Update(state);


                state.ClearTrackFade(0, 1.0f);
                state.ClearTrackFade(1, 1.0f);
                state.ClearTrackFade(2, 1.0f);
                for (var i = 0; i < interval; i++) Update(state);

                // state load
                ms.Position = 0;
                if (state.LoadFromBinary(ms))
                {
                    for (var i = 0; i < interval; i++) Update(state);
                }
                else
                {
                    Console.WriteLine("state load error : state deserialize error");
                    return false;
                }

                state.ClearTracks();
                ms.Position = 0;
                if (state.LoadFromBinary(ms))
                {
                    for (var i = 0; i < interval; i++) Update(state);
                }
                else
                {
                    Console.WriteLine("state load error : state deserialize error");
                    return false;
                }
            }

            return true;
        }
        static void Update(AnimationrigState state)
        {
            state.Update(0.1,true);
            TrackLogOut(state.TracksSafe(0), 0,"track[0]");
            TrackLogOut(state.TracksSafe(1), 1,"track[1]");
        }
        static void Main(string[] args)
        {
            if (process())
            {
                Console.WriteLine("completed.");
            }
            else
            {
                Console.WriteLine("error exists.");
            }

            Console.ReadLine();
        }
    }
}
