// Amplify Shader Editor - Visual Shader Editing Tool
// Copyright (c) Amplify Creations, Lda <info@amplify.pt>

using System;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;

namespace AmplifyShaderEditor
{
	[Serializable]
	public class TemplateNodeParent : ParentNode
	{
		protected const string ErrorMessageStr = "This node cannot be used with Surface Shaders or Shader Functions.\n\nPlease change your Shader Type to a compatible template, such as Legacy, URP, HDRP or other.";
		protected const string DataLabelStr = "Data";
		protected const string SubShaderStr = "SubShader";
		protected const string PassStr = "Pass";

		[SerializeField]
		private int m_subShaderIdx = 0;

		[SerializeField]
		private int m_passIdx = 0;

		[SerializeField]
		private int m_passLocalArrayIdx = 0;

		[SerializeField]
		protected bool m_multiPassMode = false;

		[SerializeField]
		protected string[] m_availableSubshaders;

		[SerializeField]
		protected string[] m_availablePassesLabels;

		[SerializeField]
		protected int[] m_availablePassesValues;

		[NonSerialized]
		protected TemplateMultiPass m_templateMPData = null;
		protected bool m_createAllOutputs = true;

		protected override void CommonInit( int uniqueId )
		{
			base.CommonInit( uniqueId );
			AddOutputPort( WirePortDataType.FLOAT , "Out" );
			if( m_createAllOutputs )
			{
				AddOutputPort( WirePortDataType.FLOAT , "X" );
				AddOutputPort( WirePortDataType.FLOAT , "Y" );
				AddOutputPort( WirePortDataType.FLOAT , "Z" );
				AddOutputPort( WirePortDataType.FLOAT , "W" );
			}
			m_textLabelWidth = 67;
			m_hasLeftDropdown = true;
			m_errorMessageTooltip = ErrorMessageStr;
		}

		public override void AfterCommonInit()
		{
			base.AfterCommonInit();

			if( PaddingTitleLeft == 0 )
			{
				PaddingTitleLeft = Constants.PropertyPickerWidth + Constants.IconsLeftRightMargin;
				if( PaddingTitleRight == 0 )
					PaddingTitleRight = Constants.PropertyPickerWidth + Constants.IconsLeftRightMargin;
			}
		}

		protected void ConfigurePorts()
		{
			switch( m_outputPorts[ 0 ].DataType )
			{
				default:
				{
					for( int i = 1 ; i < 5 ; i++ )
					{
						m_outputPorts[ i ].Visible = false;
					}
				}
				break;
				case WirePortDataType.FLOAT2:
				{
					for( int i = 1 ; i < 5 ; i++ )
					{
						m_outputPorts[ i ].Visible = ( i < 3 );
						if( m_outputPorts[ i ].Visible )
						{
							m_outputPorts[ i ].Name = Constants.ChannelNamesVector[ i - 1 ];
						}
					}
				}
				break;
				case WirePortDataType.FLOAT3:
				{
					for( int i = 1 ; i < 5 ; i++ )
					{
						m_outputPorts[ i ].Visible = ( i < 4 );
						if( m_outputPorts[ i ].Visible )
						{
							m_outputPorts[ i ].Name = Constants.ChannelNamesVector[ i - 1 ];
						}
					}
				}
				break;
				case WirePortDataType.FLOAT4:
				{
					for( int i = 1 ; i < 5 ; i++ )
					{
						m_outputPorts[ i ].Visible = true;
						m_outputPorts[ i ].Name = Constants.ChannelNamesVector[ i - 1 ];
					}
				}
				break;
				case WirePortDataType.COLOR:
				{
					for( int i = 1 ; i < 5 ; i++ )
					{
						m_outputPorts[ i ].Visible = true;
						m_outputPorts[ i ].Name = Constants.ChannelNamesColor[ i - 1 ];
					}
				}
				break;
			}
			m_sizeIsDirty = true;
		}

		protected virtual void OnSubShaderChange() { }
		protected virtual void OnPassChange() { }

		protected void DrawSubShaderUI()
		{
			EditorGUI.BeginChangeCheck();
			m_subShaderIdx = EditorGUILayoutPopup( SubShaderStr , m_subShaderIdx , m_availableSubshaders );
			if( EditorGUI.EndChangeCheck() )
			{
				//UpdateSubShaderAmount();
				UpdatePassAmount();
				OnSubShaderChange();
			}
		}

		protected void DrawPassUI()
		{
			EditorGUI.BeginChangeCheck();
			m_passLocalArrayIdx = EditorGUILayoutPopup( PassStr , m_passLocalArrayIdx , m_availablePassesLabels );
			if( EditorGUI.EndChangeCheck() )
			{
				m_passIdx = m_availablePassesValues[ m_passLocalArrayIdx ];
				//UpdatePassAmount();
				OnPassChange();
			}
		}

		virtual protected void CheckWarningState()
		{
			if( m_containerGraph.CurrentCanvasMode != NodeAvailability.TemplateShader )
			{
				ShowTab( NodeMessageType.Error , ErrorMessageStr );
			}
			else
			{
				m_showErrorMessage = false;
			}
		}

		public override void DrawProperties()
		{
			base.DrawProperties();			
			if ( m_showErrorMessage )
			{
				EditorGUILayout.HelpBox( ErrorMessageStr, MessageType.Error );
				return;
			}
		}

		public override void OnNodeLogicUpdate( DrawInfo drawInfo )
		{
			base.OnNodeLogicUpdate( drawInfo );
			m_showErrorMessage = ( m_containerGraph.CurrentCanvasMode != NodeAvailability.TemplateShader );
		}

		protected void FetchMultiPassTemplate( MasterNode masterNode = null )
		{
			m_multiPassMode = m_containerGraph.MultiPassMasterNodes.NodesList.Count > 0;
			if( m_multiPassMode )
			{
				m_templateMPData = ( ( ( masterNode == null ) ? m_containerGraph.CurrentMasterNode : masterNode ) as TemplateMultiPassMasterNode ).CurrentTemplate;
				if( m_templateMPData != null )
				{
					UpdateSubShaderAmount();
				}
			}
		}

		protected void UpdateSubShaderAmount()
		{
			if( m_templateMPData == null )
				m_templateMPData = ( m_containerGraph.CurrentMasterNode as TemplateMultiPassMasterNode ).CurrentTemplate;

			if( m_templateMPData != null )
			{
				int subShaderCount = m_templateMPData.SubShaders.Count;
				if( m_availableSubshaders == null || subShaderCount != m_availableSubshaders.Length )
				{
					m_availableSubshaders = new string[ subShaderCount ];
					for( int i = 0 ; i < subShaderCount ; i++ )
					{
						m_availableSubshaders[ i ] = i.ToString();
					}
				}
				m_subShaderIdx = Mathf.Min( m_subShaderIdx , subShaderCount - 1 );
				UpdatePassAmount();
			}
		}
		protected virtual bool ValidatePass( int passIdx ) { return true; }
		protected void UpdatePassAmount()
		{
			if( !m_multiPassMode )
				return;

			if( m_templateMPData == null )
				m_templateMPData = ( m_containerGraph.CurrentMasterNode as TemplateMultiPassMasterNode ).CurrentTemplate;

			List<string> passLabels = new List<string>();
			List<int> passValues = new List<int>();
			int minPassIdx = int.MaxValue;
			int passCount = m_templateMPData.SubShaders[ m_subShaderIdx ].Passes.Count;
			bool resetPassIdx = true;
			for( int i = 0 ; i < passCount ; i++ )
			{
				if( ValidatePass( i ) )
				{
					passLabels.Add( i.ToString() );
					passValues.Add( i );
					minPassIdx = Mathf.Min( minPassIdx , i );
					if( m_passIdx == i )
						resetPassIdx = false;
				}
			}
			m_availablePassesLabels = passLabels.ToArray();
			m_availablePassesValues = passValues.ToArray();
			if( resetPassIdx )
				m_passIdx = minPassIdx;

			RefreshPassLocalArrayIdx();
		}

		void RefreshPassLocalArrayIdx()
		{
			for( int i = 0 ; i < m_availablePassesValues.Length ; i++ )
			{
				if( m_availablePassesValues[ i ] == m_passIdx )
				{
					m_passLocalArrayIdx = i;
				}
			}
		}

		public override void Destroy()
		{
			base.Destroy();
			m_templateMPData = null;
		}

		public override void ReadFromString( ref string[] nodeParams )
		{
			base.ReadFromString( ref nodeParams );
			if( UIUtils.CurrentShaderVersion() > TemplatesManager.MPShaderVersion )
			{
				m_subShaderIdx = Convert.ToInt32( GetCurrentParam( ref nodeParams ) );
				m_passIdx = Convert.ToInt32( GetCurrentParam( ref nodeParams ) );
			}
		}

		public override void WriteToString( ref string nodeInfo , ref string connectionsInfo )
		{
			base.WriteToString( ref nodeInfo , ref connectionsInfo );
			IOUtils.AddFieldValueToString( ref nodeInfo , m_subShaderIdx );
			IOUtils.AddFieldValueToString( ref nodeInfo , m_passIdx );
		}

		public override void OnMasterNodeReplaced( MasterNode newMasterNode )
		{
			base.OnMasterNodeReplaced( newMasterNode );
			if( newMasterNode.CurrentMasterNodeCategory == AvailableShaderTypes.SurfaceShader )
			{
				m_content.text = m_nodeAttribs.Name;
				m_autoWrapProperties = false;
			}
			else
			{
				m_autoWrapProperties = true;
			}
			CheckWarningState();

		}
		public int SubShaderIdx { get { return m_subShaderIdx; } set { m_subShaderIdx = value; } }
		public int PassIdx { get { return m_passIdx; } set { m_passIdx = value; } }
	}
}
