using UnityEngine;
using System.Collections;
using System.Collections.Generic;
public class NeironScript : MonoBehaviour {
	public GameObject prefabNeiron;          
	public GameObject prefabSinaps;          
	public int IndexNeiron = 0;              
	private int _TypeIndexNeiron = 0;        
	public int TypeIndexNeiron               
	{
		get { return _TypeIndexNeiron; }
		set {
			if (value == 0) 
				{ _TypeIndexNeiron = value;
				  gameObject.GetComponent<SpriteRenderer>().color = new Color32(255, 255, 0, 255);
				}	
			if (value == 1) 
				{ _TypeIndexNeiron = value;
				gameObject.GetComponent<SpriteRenderer>().color = new Color32( 0, 255, 0, 255); 
				}	
			if (value == 2) 
				{ _TypeIndexNeiron = value;
				gameObject.GetComponent<SpriteRenderer>().color = new Color32(0, 255, 255, 255);
				}
			if (value == 3) 
				{ _TypeIndexNeiron = value;
				gameObject.GetComponent<SpriteRenderer>().color = new Color32(255, 255, 255, 255);
				}
			}
	}
	
	public float Adder = 0.0f; 										
	public float MaxAdder = 30f;									
	public float DampferAdder = 1.0f; 								
	public float thresholdTop = 1.0f; 								
	public float AnswerTime = 0.1f;      							
	public float TimeRepose = 0f;       							
	public bool IgnoreInput = false; 								
	public List<GameObject> hitSinaps = new List<GameObject>();  	
	public GameObject Area; 										
	private bool _ActionN;											
	
	public bool ActionN												
	{
		get { return _ActionN; }
		set 
		{
			_ActionN = value;
			if (Area != null)
			{
				gameObject.GetComponent<LineRenderer>().enabled = value; 
                bool existAction = Area.GetComponent<AreaScript>().NeironActionList.Contains(gameObject); 
				if (_ActionN && (!existAction)) Area.GetComponent<AreaScript>().NeironActionList.Add(gameObject); 
				else Area.GetComponent<AreaScript>().NeironActionList.Remove(gameObject); 
			}
		}
	}
	
	public float thresholdDown = -5.0f;			 		
	public float timeIgnore = 5.0f;   					
	public float bonusThreshold = 0f; 					
	public float DempferBonusThreshold = 1.0f; 			
	public float TimeEvaluation = 5.0f;					
	public int LimitRecurrence = 5; 					
	public float thresholdTopUp = 1.0f;					
	public bool TimeEvaluationBool = false;				
	public int LimitEvaluationInt = 0;					
	public float AdaptationTime = 0;                    
	public float thresholdAdapt = 1f;                   
	
	public float MaxForceSinaps = 100f;
	private Vector3 VectorPattern; 						
	public Vector3 VectorTrend; 						
	public float Charge = 0.0f; 						
	public float TimeCharge = 0.01f; 					
	private float changeAngle = 0f; 					
	public float FocusNeiron = 90f;						
	public bool FocusDinamic = true;                    
	public float StepFocus = 1f;						
	public float MaxFocus = 90f;						
	public float Plasticity = 1.0f; 					
	public bool PlasticityDinamic = true; 				
	public float StepPlasticity = 0.01f;				
	public float BasicPlasticity = 1.0f;				
	public bool NewNeironDinamic = true;				
	
	private float angleMin = 0f;
	private bool CorunPlasticRun = false;
	
    private Vector3 noveltyVector = Vector3.zero;
    private float noveltyFactor = 0.1f;
	IEnumerator StartSummator (){
		IgnoreInput = true;  
		gameObject.GetComponent<SpriteRenderer>().color = new Color32(255, 0, 0, 255); 
		ActionN = true; 
		yield return new WaitForSeconds(AnswerTime); 
		ActionN = false; 
		ExcitationTransfer (); 
		yield return new WaitForSeconds(TimeRepose);
		IgnoreInput = false; 
		TypeIndexNeiron = _TypeIndexNeiron; 
	}
	IEnumerator repolarizationTime (){
		IgnoreInput = true; 
		gameObject.GetComponent<SpriteRenderer>().color = new Color32(0, 0, 255, 255);
		yield return new WaitForSeconds(timeIgnore);
		IgnoreInput = false;
		TypeIndexNeiron = _TypeIndexNeiron;
	}
	IEnumerator StartModule (){
        IgnoreInput = true; 
		ActionN = true; 
		gameObject.GetComponent<SpriteRenderer>().color = new Color32(255, 0, 0, 255);
		yield return new WaitForSeconds(AnswerTime);
		ExcitationTransfer ();
		ActionN = false;
		yield return new WaitForSeconds(TimeRepose);
		IgnoreInput = false;
		TypeIndexNeiron = _TypeIndexNeiron;
		StartCoroutine ("EvaluationTime");
		if ((AdaptationTime > 0) && (thresholdTop > thresholdAdapt)) StartCoroutine ("AdaptationVoid");
        
	}
	IEnumerator EvaluationTime(){ 
		TimeEvaluationBool = true;
		yield return new WaitForSeconds(TimeEvaluation);
		TimeEvaluationBool = false;
	}
	IEnumerator AdaptationVoid(){
		yield return new WaitForSeconds(AdaptationTime);
        if (thresholdTop > thresholdAdapt) thresholdTop--;
		if ((AdaptationTime > 0) && (thresholdTop > thresholdAdapt)) StartCoroutine ("AdaptationVoid");
	}
	IEnumerator NegativeRepolarization(){
		IgnoreInput = true; 
		ActionN = true; 
        for (int i = 0; i < 16; i++)
        {  
			Charge = Area.GetComponent<AreaScript>().Spike2[i];
			if (Charge > 0) gameObject.GetComponent<SpriteRenderer>().color = new Color32(255, 0, 0, 255); 
			else gameObject.GetComponent<SpriteRenderer>().color = new Color32(0, 0, 255, 255); 
			yield return new WaitForSeconds(TimeCharge); 
		}
		Charge = 0f;
		TypeIndexNeiron = _TypeIndexNeiron;
		ActionN = false;
		IgnoreInput = false;
	}
	IEnumerator StartAssociative(){
		IgnoreInput = true;
		ActionN = true;
        StartCoroutine("PositiveRepolarization"); 
		yield return new WaitForSeconds(AnswerTime); 		
		Compass ();
	}
	IEnumerator StartWhite() {
        IgnoreInput = true;
        ActionN = true;
        StartCoroutine("PositiveRepolarization");
		yield return new WaitForSeconds(AnswerTime); 		
		ExcitationTransfer ();
	}
	IEnumerator PositiveRepolarization(){
		for (int i = 0; i < 16; i++) {
            
			Charge = Area.GetComponent<AreaScript>().Spike1[i];
			if (Charge > 0) gameObject.GetComponent<SpriteRenderer>().color = new Color32(255, 0, 0, 255); 
			else gameObject.GetComponent<SpriteRenderer>().color = new Color32(0, 0, 255, 255); 
			yield return new WaitForSeconds(TimeCharge); 
		}
		Charge = 0f; 
		TypeIndexNeiron = _TypeIndexNeiron;
		ActionN = false;
		yield return new WaitForSeconds(TimeRepose);
		IgnoreInput = false;
		StartCoroutine ("EvaluationTime");
		if ((AdaptationTime > 0) && (thresholdTop > thresholdAdapt)) StartCoroutine ("AdaptationVoid");
	}
	IEnumerator PlasticTimeCoruntine (Vector2 PT){
		CorunPlasticRun = true;
		float PlasticBuffer = Plasticity;
		Plasticity = PT.x;
		yield return new WaitForSeconds(PT.y);
		Plasticity = PlasticBuffer;
		CorunPlasticRun = false;
	}
	public void ActiveNeiron (){ 
		if (!IgnoreInput)
		{
			if (TypeIndexNeiron == 0) StartCoroutine ("StartSummator");
			if (TypeIndexNeiron == 1) StartCoroutine ("StartModule");
			if (TypeIndexNeiron == 2) StartCoroutine ("StartAssociative");
			if (TypeIndexNeiron == 3) StartCoroutine ("StartWhite");
		}
	}
	private void Compass (){
		if (Area != null){ 
			VectorPattern = Vector3.zero; 
            
			for (int i = 0; i < Area.GetComponent<AreaScript>().NeironActionList.Count; i++) { 
				if (gameObject == Area.GetComponent<AreaScript> ().NeironActionList [i]) continue; 
				Vector3 R = Area.GetComponent<AreaScript> ().NeironActionList [i].transform.position - transform.position;
                
				VectorPattern += (Area.GetComponent<AreaScript> ().NeironActionList [i].GetComponent<NeironScript> ().Charge * R.normalized);
			}
			if (VectorPattern.sqrMagnitude < 3f) VectorPattern = VectorTrend; 
			if (VectorPattern.sqrMagnitude == 0) VectorPattern = new Vector3(Random.Range(-1f, 1f), Random.Range(-1f, 1f), Random.Range(-1f, 1f)); 
            
			VectorPattern.Normalize(); 
            if (noveltyVector == Vector3.zero) noveltyVector = -VectorPattern; 
			changeAngle = Vector3.Angle(VectorPattern, noveltyVector);
			if (Area != null) Area.SendMessage("MessageOriginality", changeAngle/180);
			VectorTrend = VectorPattern; 
            noveltyVector = Vector3.Slerp(noveltyVector, VectorPattern, noveltyFactor);
            
            
            
            
			gameObject.GetComponent<LineRenderer>().SetPosition(0, transform.position);
			gameObject.GetComponent<LineRenderer>().SetPosition(1, transform.position + VectorTrend * 6);
           
			if (PlasticityDinamic) {
				if (changeAngle < 10) Plasticity -= StepPlasticity; else Plasticity += StepPlasticity; 
				if (Plasticity > 1) Plasticity = 1f;
				if (Plasticity < 0) Plasticity = 0f;
                
                
                
			}
			if (FocusDinamic){
				if (changeAngle < 10) FocusNeiron -= StepFocus; else FocusNeiron = MaxFocus;
				if (FocusNeiron < 0) FocusNeiron = 0;
                
                
                
                
			}
            
			if (NewNeironDinamic){
                if (!Physics.CheckSphere(transform.position + VectorTrend * 5, 3f))
                {   
                    
                    
					if (Area.GetComponent<AreaScript>().Global) NewNeiron(); 
					else 
					{
						if (Area.GetComponent<Collider>().bounds.Contains(transform.position + VectorTrend * 5)) NewNeiron(); 
					}
				}
				
                Collider[] hitColliders = Physics.OverlapSphere(transform.position + VectorTrend * 5, 3f); 
				foreach (Collider value in hitColliders) 
				{
					if (value.tag == "Neiron") 
					{
						bool EnableSinaps = false; 
						foreach (GameObject sinapsValue in hitSinaps) 
						{
							if (sinapsValue.GetComponent<SinapsScript>().NeironTarget == value.gameObject) {
								EnableSinaps = true; 
								break; 
							} 	
						}
						
						if (!EnableSinaps) { 
							GameObject cSinaps = Instantiate(prefabSinaps, transform.position, transform.rotation) as GameObject;
							cSinaps.transform.parent = transform;
							cSinaps.GetComponent<SinapsScript>().NeironTarget = value.gameObject;
							cSinaps.GetComponent<SinapsScript>().Force = 0f;
							hitSinaps.Add(cSinaps);
						}
					}
				}
			}
			
			angleMin = 180f;
			if (hitSinaps.Count != 0) angleMin = Vector3.Angle(hitSinaps[0].GetComponent<SinapsScript>().NeironTarget.transform.position - transform.position, VectorTrend);
			foreach(GameObject ShershSinaps in hitSinaps)
			{
				float angleShersh = Vector3.Angle(ShershSinaps.GetComponent<SinapsScript>().NeironTarget.transform.position - transform.position, VectorTrend);
				if (angleShersh < angleMin) angleMin = angleShersh;
			}
           
			if (FocusNeiron < angleMin) FocusNeiron = angleMin;
            
            
            
			
			foreach(GameObject SinapsCoeff in hitSinaps){
					if (SinapsCoeff.GetComponent<SinapsScript>().TypeSinaps == 0){
					    float angleSinaps = Vector3.Angle(SinapsCoeff.GetComponent<SinapsScript>().NeironTarget.transform.position - transform.position, VectorTrend);
					    if (angleSinaps <= FocusNeiron) SinapsCoeff.GetComponent<SinapsScript>().Force += MaxForceSinaps * Plasticity;
					    else SinapsCoeff.GetComponent<SinapsScript>().Force -= MaxForceSinaps * Plasticity;
					    SinapsCoeff.GetComponent<SinapsScript>().Force = Mathf.Clamp(SinapsCoeff.GetComponent<SinapsScript>().Force, 0, MaxForceSinaps);
				    }
			}
		}
		ExcitationTransfer ();
	}
	private void NewNeiron (){
		GameObject clone = Instantiate(prefabNeiron, transform.position + VectorTrend * 6, transform.rotation) as GameObject;
        
		if (Area != null) Area.GetComponent<AreaScript>().amount++;
		clone.GetComponent<NeironScript>().Plasticity = BasicPlasticity;
		clone.GetComponent<NeironScript>().ActionN = false;
		clone.GetComponent<NeironScript>().IgnoreInput = false;
		clone.GetComponent<NeironScript>().Adder = 0f;
		clone.GetComponent<NeironScript>().VectorTrend = Vector3.zero;
		clone.GetComponent<NeironScript>().Area = Area;
		clone.GetComponent<NeironScript>().TimeEvaluationBool = false;
		clone.GetComponent<NeironScript>().LimitEvaluationInt = 0;
		clone.GetComponent<NeironScript>().Charge = 0.0f; 
		clone.GetComponent<NeironScript>().FocusNeiron = MaxFocus;
		clone.GetComponent<NeironScript>().Plasticity =  BasicPlasticity;
		clone.GetComponent<NeironScript>().TypeIndexNeiron = 2;
        clone.GetComponent<NeironScript>().noveltyVector = Vector3.zero;
        clone.GetComponent<NeironScript>().VectorTrend = Vector3.zero;
		clone.GetComponent<LineRenderer>().SetPosition(0, clone.transform.position);
		clone.GetComponent<LineRenderer>().SetPosition(1, clone.transform.position);
		clone.SendMessage("StopNeiron"); 
		GameObject ManagerObj = GameObject.Find("Manager"); 
		ManagerObj.GetComponent<ManagerScript>().EndIndexNeiron++;
		clone.GetComponent<NeironScript>().IndexNeiron = ManagerObj.GetComponent<ManagerScript>().EndIndexNeiron;
		clone.name = "Neiron" + clone.GetComponent<NeironScript>().IndexNeiron;
        foreach (GameObject sd in clone.GetComponent<NeironScript>().hitSinaps) Destroy(sd); 
		clone.GetComponent<NeironScript>().hitSinaps.Clear(); 
	}
	void FixedUpdate(){ 
		if (!IgnoreInput) 
		{
			if (TypeIndexNeiron == 0)  
			{
				if (Adder > thresholdTop) 
				{
					StartCoroutine ("StartSummator"); 
				}
			}
			if (TypeIndexNeiron == 1) 
			{
				if (Adder > thresholdTop + bonusThreshold) 
				{
					
					if (TimeEvaluationBool) 
					{                       
						LimitEvaluationInt++; 
						StopCoroutine("EvaluationTime"); 
						TimeEvaluationBool = false; 
					}
					else LimitEvaluationInt = 0; 
					if ((LimitEvaluationInt > LimitRecurrence) && (bonusThreshold == 0)) thresholdTop += thresholdTopUp; 
					StopCoroutine ("AdaptationVoid");  
					StartCoroutine ("StartModule"); 
					
				}
				if (Adder < thresholdDown) 
				{
					if (Area != null) StartCoroutine ("repolarizationTime"); 
				}
			}
			if (TypeIndexNeiron == 2) 
			{
				if (Adder > thresholdTop + bonusThreshold) 
				{
					if (TimeEvaluationBool) 
					{
						LimitEvaluationInt++; 
						StopCoroutine("EvaluationTime");
						TimeEvaluationBool = false;
					}
					else LimitEvaluationInt = 0; 
					if ((LimitEvaluationInt > LimitRecurrence) && (bonusThreshold == 0)) thresholdTop += thresholdTopUp; 
					StopCoroutine ("AdaptationVoid");
					StartCoroutine ("StartAssociative"); 
				}
				if (Adder < thresholdDown) 
				{
					StartCoroutine ("NegativeRepolarization");  
				}
			}
			if (TypeIndexNeiron == 3) 
			{
				if (Adder > thresholdTop + bonusThreshold)
				{
					if (TimeEvaluationBool)
					{
						LimitEvaluationInt++;
						StopCoroutine("EvaluationTime");
						TimeEvaluationBool = false;
					}
					else LimitEvaluationInt = 0;
					if ((LimitEvaluationInt > LimitRecurrence) && (bonusThreshold == 0)) thresholdTop += thresholdTopUp;
					StopCoroutine ("AdaptationVoid");
					StartCoroutine ("StartWhite");  
				}
				if (Adder < thresholdDown)
				{
					StartCoroutine ("NegativeRepolarization");  
				}
			}
		}
        if (Mathf.Abs(Adder) <= DampferAdder) Adder = 0f; 
		if (Adder > DampferAdder) Adder -= DampferAdder;
		if (Adder < -DampferAdder) Adder += DampferAdder;
        if (Mathf.Abs(bonusThreshold) <= DempferBonusThreshold) bonusThreshold = 0f; 
		if (bonusThreshold > DempferBonusThreshold) bonusThreshold -= DempferBonusThreshold;
		if (bonusThreshold < -DempferBonusThreshold) bonusThreshold += DempferBonusThreshold;
	} 
	private void ExcitationTransfer () 
	{
		foreach (GameObject value in hitSinaps) 
		{
			int T = value.GetComponent<SinapsScript>().TypeSinaps; 
			float F = value.GetComponent<SinapsScript>().Force; 
			GameObject NT = value.GetComponent<SinapsScript>().NeironTarget;
			if (T == 0) NT.SendMessage("AddSummator", F);
			if (T == 1) NT.SendMessage("AddTActual", F);
			if (T == 2) NT.SendMessage("ActiveNeiron");
            if (T == 3) NT.SendMessage("AddSummator", F);
			value.GetComponent<SinapsScript>().GoAction = true;
		}
	}
	public void AddSummator (float Summ) 
	{
		Adder += Summ;
		if (Adder > MaxAdder) Adder = MaxAdder;
        if (Adder < - MaxAdder) Adder = -MaxAdder;
	}
	public void AddTActual (float T)
	{
		bonusThreshold += T;
		if (bonusThreshold + thresholdTop < 0f) bonusThreshold = - thresholdTop + 0.0001f;
	}
	public void StopNeiron(){
		StopAllCoroutines();
	}
	public void plasticSetTime (Vector2 plasticTime){
        
        
		if (!CorunPlasticRun) StartCoroutine("PlasticTimeCoruntine", plasticTime);
        if (TypeIndexNeiron == 2) thresholdTop = thresholdAdapt;
	}
}