using System;
using System.Collections.Generic;
using UnityEngine;
using T = System.Tuple<UnityEngine.GameObject, UnityEngine.Matrix4x4>;

public class TreeTurtle : TurtleLSystemEnvironment
{
    public GameObject branch;
    public GameObject leaf;
    public GameObject apple;
    public float angle;

    private Matrix4x4 RootGrowth(float age)
    {
        return Matrix4x4.TRS(
        new Vector3(
        0.0f,
        0.2f,
        0.0f),
        Quaternion.identity,
        new Vector3(
        0.02f + age * 0.1f,
        0.015f + age * 0.1f,
        0.02f + age * 0.1f));
    }

    private Matrix4x4 BranchGrowth(float age)
    {
        return Matrix4x4.TRS(
        new Vector3(
        0.0f,
        0.15f,
        0.0f),
        Quaternion.identity,
        new Vector3(
        0.015f + age * 0.1f,
        0.05f + age * 0.1f,
        0.015f + age * 0.1f));
    }

    private Matrix4x4 LeafGrowth(float age)
    {
        return Matrix4x4.TRS(
        new Vector3(
        0.02f,
        0.0f,
        0.0f),
        Quaternion.identity,
        new Vector3(
        0.03f + age * 0.1f,
        0.03f + age * 0.1f,
        0.03f + age * 0.1f));
    }

    private Matrix4x4 AppleGrowth(float age)
    {
        return Matrix4x4.TRS(
        new Vector3(
        0.04f,
        0.15f,
        0.0f),
        Quaternion.identity,
        new Vector3(
        0.03f + age * 0.1f,
        0.03f + age * 0.1f,
        0.03f + age * 0.1f));
    }

    private Func<float[], Matrix4x4> Roation(Vector3 axis)
    {
        Matrix4x4 f(float[] args)
        {
            if (args.Length == 0)
            {
                return Matrix4x4.Rotate(Quaternion.AngleAxis(angle, axis));
            }
            else
            {
                return Matrix4x4.Rotate(Quaternion.AngleAxis(args[0], axis));
            }
        }
        return f;
    }

    protected override void initLiteralInterpretation()
    {
        turtleInterpretation = new Dictionary<string, Func<float[], T>>
        {
            { "+", (float[] args) => new T(null, Roation(Vector3.back)(args)) },
            { "-", (float[] args) => new T(null, Roation(Vector3.forward)(args)) },

            { "\\", (float[] args) => new T(null, Roation(Vector3.down)(args)) },
            { "/", (float[] args) => new T(null, Roation(Vector3.up)(args)) },

            { "^", (float[] args) => new T(null, Roation(Vector3.left)(args)) },
            { "&", (float[] args) => new T(null, Roation(Vector3.right)(args)) },

            { "f", (float[] args) => new T(null, Matrix4x4.Translate(Vector3.left * args[0])) },
            { "I", (float[] args) => new T(null, Matrix4x4.identity) },
            { "S", (float[] args) => new T(null, Matrix4x4.identity) },

            { "R", (float[] args) => new T(branch, RootGrowth(args[0]))},
            { "B", (float[] args) => new T(branch, BranchGrowth(args[0]))},
            { "N", (float[] args) => new T(branch, BranchGrowth(1))},
            { "A", (float[] args) => new T(apple, AppleGrowth(args[0]))},
            { "L", (float[] args) => new T(leaf, LeafGrowth(args[0]))},

            //Wildcard how to represent any other symbol
            { "*.*", (float[] args) => new T(branch, BranchGrowth(args[0]))}
        };
    }
}