context: using UnityEngine;
  using System.Collections;
  using System.Collections.Generic;
  using System.Reflection;
  using System;
  
  using Holoville.HOTween;
  using Holoville.HOTween.Plugins;
  
  [AddComponentMenu("")]
  public class AMPropertyKey : AMKey {
      public int valueType;
  
      public Component component;
      public int endFrame;
      public string propertyName;
      public string fieldName;
      public string methodName;
      public string[] methodParameterTypes;
      private MethodInfo cachedMethodInfo;
      private PropertyInfo cachedPropertyInfo;
      private FieldInfo cachedFieldInfo;
      public PropertyInfo propertyInfo {
          get {
              if(cachedPropertyInfo != null) return cachedPropertyInfo;
              if(!component || propertyName == null) return null;
              cachedPropertyInfo = component.GetType().GetProperty(propertyName);
              return cachedPropertyInfo;
          }
          set {
              if(value != null) propertyName = value.Name;
              else propertyName = null;
              cachedPropertyInfo = value;
  
          }
      }
      public FieldInfo fieldInfo {
          get {
              if(cachedFieldInfo != null) return cachedFieldInfo;
              if(!component || fieldName == null) return null;
              cachedFieldInfo = component.GetType().GetField(fieldName);
              return cachedFieldInfo;
          }
          set {
              if(value != null) fieldName = value.Name;
              else fieldName = null;
              cachedFieldInfo = value;
          }
      }		// holds a field such as variables for user scripts, should be null if property is used
      public MethodInfo methodInfo {
          get {
              if(cachedMethodInfo != null) return cachedMethodInfo;
              if(!component || methodName == null) return null;
              Type[] t = new Type[methodParameterTypes.Length];
              for(int i = 0; i < methodParameterTypes.Length; i++) t[i] = Type.GetType(methodParameterTypes[i]);
              cachedMethodInfo = component.GetType().GetMethod(methodName, t);
              return cachedMethodInfo;
          }
          set {
              if(value != null) methodName = value.Name;
              else methodName = null;
              cachedMethodInfo = value;
          }
      }
  
  
      //union for single values
      public double val;	// value as double
  
      //union for vectors, color, rect
      public Vector4 vect4;
      public Vector2 vect2 { get { return new Vector2(vect4.x, vect4.y); } set { vect4.Set(value.x, value.y, 0, 0); } }
      public Vector3 vect3 { get { return new Vector3(vect4.x, vect4.y, vect4.z); } set { vect4.Set(value.x, value.y, value.z, 0); } }
      public Color color { get { return new Color(vect4.x, vect4.y, vect4.z, vect4.w); } set { vect4.Set(value.r, value.g, value.b, value.a); } }
      public Rect rect { get { return new Rect(vect4.x, vect4.y, vect4.z, vect4.w); } set { vect4.Set(value.xMin, value.yMin, value.width, value.height); } }
      public Quaternion quat { get { return new Quaternion(vect4.x, vect4.y, vect4.z, vect4.w); } set { vect4.Set(value.x, value.y, value.z, value.w); } }
  
      public double end_val;			// value as double (includes int/long)
      public Vector4 end_vect4;
  
      public Vector2 end_vect2 { get { return new Vector2(end_vect4.x, end_vect4.y); } set { end_vect4.Set(value.x, value.y, 0, 0); } }
      public Vector3 end_vect3 { get { return new Vector3(end_vect4.x, end_vect4.y, end_vect4.z); } set { end_vect4.Set(value.x, value.y, value.z, 0); } }
      public Color end_color { get { return new Color(end_vect4.x, end_vect4.y, end_vect4.z, end_vect4.w); } set { end_vect4.Set(value.r, value.g, value.b, value.a); } }
      public Rect end_rect { get { return new Rect(end_vect4.x, end_vect4.y, end_vect4.z, end_vect4.w); } set { end_vect4.Set(value.xMin, value.yMin, value.width, value.height); } }
      public Quaternion end_quat { get { return new Quaternion(end_vect4.x, end_vect4.y, end_vect4.z, end_vect4.w); } set { end_vect4.Set(value.x, value.y, value.z, value.w); } }
  
      public bool setValue(float val) {
          if(this.val != (double)val) {
              this.val = (double)val;
              return true;
          }
          return false;
      }
      public bool setValue(Quaternion quat) {
          if(this.quat != quat) {
              this.quat = quat;
              return true;
          }
          return false;
      }
      public bool setValue(Vector4 vect4) {
          if(this.vect4 != vect4) {
              this.vect4 = vect4;
              return true;
          }
          return false;
      }
      public bool setValue(Vector3 vect3) {
          if(this.vect3 != vect3) {
              this.vect3 = vect3;
              return true;
          }
          return false;
      }
      public bool setValue(Color color) {
          if(this.color != color) {
              this.color = color;
              return true;
          }
          return false;
      }
      public bool setValue(Rect rect) {
          if(this.rect != rect) {
              this.rect = rect;
              return true;
          }
          return false;
      }
      public bool setValue(Vector2 vect2) {
          if(this.vect2 != vect2) {
              this.vect2 = vect2;
              return true;
          }
          return false;
      }
      // set value from double
      public bool setValue(double val) {
          if(this.val != val) {
              this.val = val;
              return true;
          }
          return false;
      }
      // set value from int
      public bool setValue(int val) {
          if(this.val != (double)val) {
              this.val = (double)val;
              return true;
          }
          return false;
      }
      // set value from long
      public bool setValue(long val) {
          if(this.val != (double)val) {
              this.val = (double)val;
              return true;
          }
          return false;
      }
  
      // copy properties from key
      public override AMKey CreateClone() {
  
          AMPropertyKey a = gameObject.AddComponent<AMPropertyKey>();
          a.enabled = false;
          a.frame = frame;
          a.val = val;
          a.vect4 = vect4;
          a.easeType = easeType;
          a.customEase = new List<float>(customEase);
  
          return a;
      }
  
      #region action
      public override int getNumberOfFrames() {
          return endFrame - frame;
      }
      public float getTime(int frameRate) {
          return (float)getNumberOfFrames() / (float)frameRate;
      }
      public override Tweener buildTweener(Sequence sequence, int frameRate) {
          if(targetsAreEqual()) return null;
          if((endFrame == -1) || !component || ((fieldInfo == null) && (propertyInfo == null) && (methodInfo == null))) return null;
  
          string varName = null;
  
          if(fieldInfo != null) {
              varName = fieldName;
          }
          else if(propertyInfo != null) {
              varName = propertyName;
          }
          //return HOTween.To(obj, getTime(frameRate), new TweenParms().Prop(isLocal ? "localRotation" : "rotation", new AMPlugQuaternionSlerp(endRotation)).Ease(easeCurve));
          if(varName != null) {
              if(hasCustomEase()) {
                  switch((AMPropertyTrack.ValueType)valueType) {
                      case AMPropertyTrack.ValueType.Integer:
                          return HOTween.To(component, getTime(frameRate), new TweenParms().Prop(varName, Convert.ToInt32(end_val)).Ease(easeCurve));
                      case AMPropertyTrack.ValueType.Float:
                          return HOTween.To(component, getTime(frameRate), new TweenParms().Prop(varName, Convert.ToSingle(end_val)).Ease(easeCurve));
                      case AMPropertyTrack.ValueType.Double:
                          return HOTween.To(component, getTime(frameRate), new TweenParms().Prop(varName, new AMPlugDouble(end_val)).Ease(easeCurve));
                      case AMPropertyTrack.ValueType.Long:
                          return HOTween.To(component, getTime(frameRate), new TweenParms().Prop(varName, new AMPlugLong(Convert.ToInt64(end_val))).Ease(easeCurve));
                      case AMPropertyTrack.ValueType.Vector2:
                          return HOTween.To(component, getTime(frameRate), new TweenParms().Prop(varName, end_vect2).Ease(easeCurve));
                      case AMPropertyTrack.ValueType.Vector3:
                          return HOTween.To(component, getTime(frameRate), new TweenParms().Prop(varName, end_vect3).Ease(easeCurve));
                      case AMPropertyTrack.ValueType.Color:
                          return HOTween.To(component, getTime(frameRate), new TweenParms().Prop(varName, end_color).Ease(easeCurve));
                      case AMPropertyTrack.ValueType.Rect:
                          return HOTween.To(component, getTime(frameRate), new TweenParms().Prop(varName, end_rect).Ease(easeCurve));
                      case AMPropertyTrack.ValueType.Vector4:
                          return HOTween.To(component, getTime(frameRate), new TweenParms().Prop(varName, end_vect4).Ease(easeCurve));
                      case AMPropertyTrack.ValueType.Quaternion:
                          return HOTween.To(component, getTime(frameRate), new TweenParms().Prop(varName, new AMPlugQuaternionSlerp(end_quat)).Ease(easeCurve));
                  }
              }
              else {
                  switch((AMPropertyTrack.ValueType)valueType) {
                      case AMPropertyTrack.ValueType.Integer:
                          return HOTween.To(component, getTime(frameRate), new TweenParms().Prop(varName, Convert.ToInt32(end_val)).Ease((EaseType)easeType, amplitude, period));
                      case AMPropertyTrack.ValueType.Float:
                          return HOTween.To(component, getTime(frameRate), new TweenParms().Prop(varName, Convert.ToSingle(end_val)).Ease((EaseType)easeType, amplitude, period));
                      case AMPropertyTrack.ValueType.Double:
                          return HOTween.To(component, getTime(frameRate), new TweenParms().Prop(varName, new AMPlugDouble(end_val)).Ease((EaseType)easeType, amplitude, period));
                      case AMPropertyTrack.ValueType.Long:
                          return HOTween.To(component, getTime(frameRate), new TweenParms().Prop(varName, new AMPlugLong(Convert.ToInt64(end_val))).Ease((EaseType)easeType, amplitude, period));
                      case AMPropertyTrack.ValueType.Vector2:
                          return HOTween.To(component, getTime(frameRate), new TweenParms().Prop(varName, end_vect2).Ease((EaseType)easeType, amplitude, period));
                      case AMPropertyTrack.ValueType.Vector3:
                          return HOTween.To(component, getTime(frameRate), new TweenParms().Prop(varName, end_vect3).Ease((EaseType)easeType, amplitude, period));
                      case AMPropertyTrack.ValueType.Color:
                          return HOTween.To(component, getTime(frameRate), new TweenParms().Prop(varName, end_color).Ease((EaseType)easeType, amplitude, period));
                      case AMPropertyTrack.ValueType.Rect:
                          return HOTween.To(component, getTime(frameRate), new TweenParms().Prop(varName, end_rect).Ease((EaseType)easeType, amplitude, period));
                      case AMPropertyTrack.ValueType.Vector4:
                          return HOTween.To(component, getTime(frameRate), new TweenParms().Prop(varName, end_vect4).Ease((EaseType)easeType, amplitude, period));
                      case AMPropertyTrack.ValueType.Quaternion:
                          return HOTween.To(component, getTime(frameRate), new TweenParms().Prop(varName, new AMPlugQuaternionSlerp(end_quat)).Ease((EaseType)easeType, amplitude, period));
                  }
              }
          }
  
          Debug.LogError("Animator: No FieldInfo or PropertyInfo set.");
          return null;
      }
  
      public string getName() {
          if(fieldInfo != null) return fieldInfo.Name;
          else if(propertyInfo != null) return propertyInfo.Name;
          else if(methodInfo != null) {
          }
          return "Unknown";
      }
  
      public string getFloatArrayString(int codeLanguage, List<float> ls) {
          string s = "";
          if(codeLanguage == 0) s += "new float[]{";
          else s += "[";
          for(int i = 0; i < ls.Count; i++) {
              s += ls[i].ToString();
              if(codeLanguage == 0) s += "f";
              if(i < ls.Count - 1) s += ", ";
          }
          if(codeLanguage == 0) s += "}";
          else s += "]";
          return s;
      }
      public string getValueString(bool brief) {
          string s = "";
          if(AMPropertyTrack.isValueTypeNumeric(valueType)) {
              //s+= start_val.ToString();
              s += formatNumeric(val);
              if(!brief && endFrame != -1) s += " -> " + formatNumeric(end_val);
              //if(!brief && endFrame != -1) s += " -> "+end_val.ToString();
          }
          else if(valueType == (int)AMPropertyTrack.ValueType.Vector2) {
              s += vect2.ToString();
  
gt:             if(!brief && endFrame != -1) s += " -> " + end_vect2.ToString();