Editor/Inspector/TypePropertyEditors.cs
using Editor;
using System;
using System.Globalization;
using System.Linq;

namespace XGUI.XGUIEditor
{
	/// <summary>
	/// Text editor with a simple line edit control
	/// </summary>
	public class TextPropertyEditor : PropertyEditor
	{
		private LineEdit _editor;
		private Widget _rootWidget;

		public TextPropertyEditor( string propertyName, string displayName, bool isStyle = false )
			: base( propertyName, displayName, isStyle )
		{
		}

		public override Widget CreateUI( Layout layout )
		{
			// Create a container widget for the editor
			_rootWidget = new Widget( null );
			_rootWidget.Layout = Layout.Row();
			_rootWidget.Layout.Margin = 0;
			_rootWidget.Layout.Spacing = 2;

			_rootWidget.Layout.Add( new Editor.Label( DisplayName ) { FixedWidth = 100 } );
			_editor = _rootWidget.Layout.Add( new LineEdit(), 1 );
			_editor.TextChanged += ( text ) => NotifyValueChanged( text );

			// Add the root widget to the parent layout
			layout.Add( _rootWidget );

			// Set the RootWidget property
			RootWidget = _rootWidget;
			return _rootWidget;
		}

		public override void SetValueSilently( string value )
		{
			if ( _editor != null )
			{
				_editor.Text = value ?? "";
			}
		}
	}

	/// <summary>
	/// Numeric editor for float values with unit handling
	/// </summary>
	public class FloatPropertyEditor : PropertyEditor
	{
		private LineEdit _editor;
		private string _unit = "px";
		private Widget _rootWidget;

		public FloatPropertyEditor( string propertyName, string displayName, bool isStyle = false, string unit = "px" )
			: base( propertyName, displayName, isStyle )
		{
			_unit = unit;
		}

		public override Widget CreateUI( Layout layout )
		{
			// Create a container widget for the editor
			_rootWidget = new Widget( null );
			_rootWidget.Layout = Layout.Row();
			_rootWidget.Layout.Margin = 0;
			_rootWidget.Layout.Spacing = 2;

			_rootWidget.Layout.Add( new Editor.Label( DisplayName ) { FixedWidth = 100 } );
			_editor = _rootWidget.Layout.Add( new LineEdit(), 1 );
			_editor.TextChanged += ( text ) =>
			{
				if ( float.TryParse( text, NumberStyles.Float, CultureInfo.InvariantCulture, out float value ) )
				{
					NotifyValueChanged( value );
				}
			};

			// Add the root widget to the parent layout
			layout.Add( _rootWidget );

			// Set the RootWidget property
			RootWidget = _rootWidget;
			return _rootWidget;
		}

		public override void SetValueSilently( string value )
		{
			if ( _editor == null ) return;

			// If the value is empty/null, leave the editor blank instead of defaulting to zero
			if ( string.IsNullOrEmpty( value ) )
			{
				_editor.Text = "";
				return;
			}

			// Remove unit if present
			foreach ( var unit in new[] { "px", "%", "em", "rem", "vh", "vw" } )
			{
				if ( value.EndsWith( unit, StringComparison.OrdinalIgnoreCase ) )
				{
					value = value.Substring( 0, value.Length - unit.Length );
					break;
				}
			}

			// Parse and set value
			if ( float.TryParse( value, NumberStyles.Float, CultureInfo.InvariantCulture, out float floatValue ) )
			{
				_editor.Text = floatValue.ToString( CultureInfo.InvariantCulture );
			}
			else
			{
				// Leave blank if parsing fails instead of defaulting to zero
				_editor.Text = "";
			}
		}

		// Helper to get the formatted value with units
		public string GetFormattedValue()
		{
			if ( _editor == null || string.IsNullOrEmpty( _editor.Text ) ) return "";

			if ( float.TryParse( _editor.Text, NumberStyles.Float, CultureInfo.InvariantCulture, out float value ) )
			{
				return value.ToString( CultureInfo.InvariantCulture ) + _unit;
			}

			return "";
		}
	}


	/// <summary>
	/// Color editor with a color picker
	/// </summary>
	public class ColorPropertyEditor : PropertyEditor
	{
		private ColorPicker _colorPicker;
		private Widget _rootWidget;
		private bool _hasSetInitialValue = false;

		public ColorPropertyEditor( string propertyName, string displayName, bool isStyle = false )
			: base( propertyName, displayName, isStyle )
		{
		}

		public override Widget CreateUI( Layout layout )
		{
			// Create a container widget for the editor
			_rootWidget = new Widget( null );
			_rootWidget.Layout = Layout.Row();
			_rootWidget.Layout.Margin = 0;
			_rootWidget.Layout.Spacing = 2;

			_rootWidget.Layout.Add( new Editor.Label( DisplayName ) { FixedWidth = 100 } );
			_colorPicker = _rootWidget.Layout.Add( new Editor.ColorPicker( null ), 1 );

			// Don't set a default initial color - leave as default from ColorPicker
			_hasSetInitialValue = false;

			_colorPicker.ValueChanged = ( color ) => NotifyValueChanged( color );

			// Add the root widget to the parent layout
			layout.Add( _rootWidget );

			// Set the RootWidget property
			RootWidget = _rootWidget;
			return _rootWidget;
		}

		public override void SetValueSilently( string cssColor )
		{
			if ( _colorPicker == null ) return;

			// If the value is empty and we've never set a value, don't do anything
			// This prevents overriding with a default value
			if ( string.IsNullOrEmpty( cssColor ) && !_hasSetInitialValue )
			{
				return;
			}

			if ( Color.TryParse( cssColor, out var color ) )
			{
				_colorPicker.Value = color;
				_hasSetInitialValue = true;
			}
		}

		// Helper to get CSS hex string
		public string GetHexString()
		{
			if ( _colorPicker == null || !_hasSetInitialValue ) return "";

			var color = _colorPicker.Value;
			if ( color.a < 1.0f )
			{
				return $"#{(int)(color.r * 255):X2}{(int)(color.g * 255):X2}{(int)(color.b * 255):X2}{(int)(color.a * 255):X2}";
			}
			else
			{
				return $"#{(int)(color.r * 255):X2}{(int)(color.g * 255):X2}{(int)(color.b * 255):X2}";
			}
		}
	}

	/// <summary>
	/// Boolean editor with a checkbox
	/// </summary>
	public class BoolPropertyEditor : PropertyEditor
	{
		private Editor.Checkbox _checkbox;
		private Widget _rootWidget;

		public BoolPropertyEditor( string propertyName, string displayName, bool isStyle = false )
			: base( propertyName, displayName, isStyle )
		{
		}

		public override Widget CreateUI( Layout layout )
		{
			// Create a container widget for the editor
			_rootWidget = new Widget( null );
			_rootWidget.Layout = Layout.Row();
			_rootWidget.Layout.Margin = 0;
			_rootWidget.Layout.Spacing = 2;

			_rootWidget.Layout.Add( new Editor.Label( DisplayName ) { FixedWidth = 100 } );
			_checkbox = _rootWidget.Layout.Add( new Editor.Checkbox() );
			_checkbox.StateChanged = ( state ) => NotifyValueChanged( _checkbox.Value );

			// Add the root widget to the parent layout
			layout.Add( _rootWidget );

			// Set the RootWidget property
			RootWidget = _rootWidget;
			return _rootWidget;
		}

		public override void SetValueSilently( string value )
		{
			if ( _checkbox == null ) return;
			_checkbox.Value = !string.IsNullOrEmpty( value ) && value != "false" && value != "0";
		}
	}

	/// <summary>
	/// Dropdown editor with a list of options
	/// </summary>
	public class DropdownPropertyEditor : PropertyEditor
	{
		private Editor.ComboBox _dropdown;
		private Widget _rootWidget;
		private readonly string[] _options;

		public DropdownPropertyEditor( string propertyName, string displayName, string[] options, bool isStyle = false )
			: base( propertyName, displayName, isStyle )
		{
			_options = options;
		}

		public override Widget CreateUI( Layout layout )
		{
			// Create a container widget for the editor
			_rootWidget = new Widget( null );
			_rootWidget.Layout = Layout.Row();
			_rootWidget.Layout.Margin = 0;
			_rootWidget.Layout.Spacing = 2;

			_rootWidget.Layout.Add( new Editor.Label( DisplayName ) { FixedWidth = 100 } );
			_dropdown = _rootWidget.Layout.Add( new Editor.ComboBox(), 1 );

			foreach ( var option in _options )
			{
				_dropdown.AddItem( option );
			}

			_dropdown.TextChanged += () => NotifyValueChanged( _dropdown.CurrentText );
			_dropdown.ItemChanged += () => NotifyValueChanged( _dropdown.CurrentText );

			// Add the root widget to the parent layout
			layout.Add( _rootWidget );

			// Set the RootWidget property
			RootWidget = _rootWidget;
			return _rootWidget;
		}

		public override void SetValueSilently( string value )
		{
			if ( _dropdown == null ) return;

			// Try to find a matching option
			if ( _options.Contains( value, StringComparer.OrdinalIgnoreCase ) )
			{
				_dropdown.CurrentText = value;
			}
			else if ( _options.Length > 0 )
			{
				_dropdown.CurrentText = _options[0]; // Default to first option
			}
		}
	}
}