﻿using System;
using Oni.Imaging;

namespace Oni.Particles
{
    internal class Value
    {
        public const int ByteSize = 28;
        public static readonly Value Empty = new Value(ValueType.Variable, string.Empty);
        public static readonly Value FloatZero = new Value(0.0f);
        public static readonly Value FloatOne = new Value(1.0f);

        #region Private data
        private ValueType type;
        private string name;
        private float f1, f2;
        private Color c1, c2;
        private int i;
        #endregion

        public Value(ValueType type, float value1, float value2)
        {
            this.type = type;
            this.f1 = value1;
            this.f2 = value2;
        }

        public Value(float value)
            : this(ValueType.Float, value, 0.0f)
        {
        }

        public Value(int value)
        {
            this.type = ValueType.Int32;
            this.i = value;
        }

        public Value(ValueType type, string name)
        {
            this.type = type;
            this.name = name;
        }

        public Value(Color color)
            : this(ValueType.Color, color, Color.Black)
        {
        }

        public Value(ValueType type, Color color1, Color color2)
        {
            this.type = type;
            this.c1 = color1;
            this.c2 = color2;
        }

        public static Value Read(BinaryReader reader)
        {
            int startPosition = (int)reader.Position;

            ValueType type = (ValueType)reader.ReadInt32();
            Value result = null;

            switch (type)
            {
                case ValueType.Variable:
                    string name = reader.ReadString(16);
                    if (!string.IsNullOrEmpty(name))
                        result = new Value(type, name);
                    break;

                case ValueType.InstanceName:
                    result = new Value(type, reader.ReadString(16));
                    break;

                case ValueType.Float:
                    result = new Value(reader.ReadSingle());
                    break;

                case ValueType.FloatRandom:
                case ValueType.FloatBellCurve:
                case ValueType.TimeCycle:
                    result = new Value(type, reader.ReadSingle(), reader.ReadSingle());
                    break;

                case ValueType.Color:
                    result = new Value(reader.ReadColor());
                    break;

                case ValueType.ColorRandom:
                case ValueType.ColorBellCurve:
                    result = new Value(type, reader.ReadColor(), reader.ReadColor());
                    break;

                case ValueType.Int32:
                    result = new Value(reader.ReadInt32());
                    break;
            }

            reader.Position = startPosition + ByteSize;

            return result;
        }

        public void Write(BinaryWriter writer)
        {
            int startPosition = (int)writer.Position;

            writer.Write((int)type);

            switch (type)
            {
                case ValueType.Variable:
                case ValueType.InstanceName:
                    writer.Write(name, 16);
                    break;

                case ValueType.Float:
                    writer.Write(f1);
                    break;

                case ValueType.FloatRandom:
                case ValueType.FloatBellCurve:
                case ValueType.TimeCycle:
                    writer.Write(f1);
                    writer.Write(f2);
                    break;

                case ValueType.Color:
                    writer.Write(c1);
                    break;

                case ValueType.ColorRandom:
                case ValueType.ColorBellCurve:
                    writer.Write(c1);
                    writer.Write(c2);
                    break;

                case ValueType.Int32:
                    writer.Write(i);
                    break;
            }

            writer.Position = startPosition + ByteSize;
        }

        public ValueType Type => type;
        public string Name => name;
        public float Float1 => f1;
        public float Float2 => f2;
        public Color Color1 => c1;
        public Color Color2 => c2;
        public int Int => i;
    }
}
