//..............................................................................
//
// Ninja UI - property grid
//

import "ui_ListItem.jnc"
import "ui_Dictionary.jnc"
import "std_HashTable.jnc"

namespace ui {

//! \addtogroup api-ui
//! @{

//..............................................................................

opaque class Property {
	Property* readonly m_parent;
	string_t autoget property m_name;
	string_t autoget property m_toolTip;
	string_t autoget property m_valueToolTip;
	bool autoget property m_isEnabled;

	destruct();

	void addChildProperty(
		Property* prop,
		Property* beforeProp = null
	);

	void removeChildProperty(Property* prop);
}

//..............................................................................

class GroupProperty: Property {
	construct(string_t name);
}

//..............................................................................

class BoolProperty: Property {
	construct(string_t name);

	bool bindable autoget property m_value;
	bool autoget property m_isGroupEnabler;
}

//..............................................................................

class IntProperty: Property {
	construct(string_t name);

	int bindable autoget property m_value;
	int autoget property m_minValue;
	int autoget property m_maxValue;
	int autoget property m_spinBoxStep;
}

//..............................................................................

class StringProperty: Property {
	construct(string_t name);

	string_t bindable autoget property m_value;
	string_t autoget property m_placeholderText;
	bool autoget property m_isPassword;
}

//..............................................................................

typedef ListItem EnumPropertyOption;

// . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

opaque class EnumProperty: Property {
	property m_value {
		variant_t autoget m_value;
		void set(variant_t value);
		bindable alias m_onPropChanged = m_onChanged;
	}

	property m_currentIndex {
		size_t autoget m_value;
		void set(size_t value);
		bindable alias m_onPropChanged = m_onChanged;
	}

	property m_currentText {
		string_t get();
		bindable alias m_onPropChanged = m_onChanged;
	}

	event m_onChanged();

	construct(string_t name);
	destruct();

	void setOptions(
		EnumPropertyOption const* optionArray,
		size_t count
	);

	size_t addOption(
		string_t text,
		variant_t value = null
	);

	void clear();
}

// . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

opaque class ComboProperty: Property {
	string_t bindable autoget property m_value;
	string_t autoget property m_placeholderText;

	construct(string_t name);
	destruct();

	void setOptions(
		EnumPropertyOption const* optionArray, // option.value should be 'null' or string value
		size_t count
	);

	void selectOption(size_t index);
}

//..............................................................................

struct FlagPropertyOption {
	string_t m_text;
	uint_t m_value;
}

// . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

opaque class FlagProperty: Property {
	uint_t bindable autoget property m_value;

	construct(string_t name);
	destruct();

	void setOptions(
		FlagPropertyOption const* optionArray,
		size_t count
	);
}

//..............................................................................

class ColorProperty: Property {
	uint_t bindable autoget property m_value;

	construct(string_t name);
}

//..............................................................................

class ActionProperty: Property {
	function* m_onAction();

	construct(string_t name);
}

//..............................................................................

enum FilePropertyMode {
	AnyFile,
	ExistingFile,
	Directory,
	ExistingFiles,
};

// . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

bitflag enum FilePropertyOptions {
    ShowDirsOnly                = 0x00000001,
    DontResolveSymlinks         = 0x00000002,
    DontConfirmOverwrite        = 0x00000004,
    DontUseSheet                = 0x00000008,
    DontUseNativeDialog         = 0x00000010,
    ReadOnly                    = 0x00000020,
    HideNameFilterDetails       = 0x00000040,
    DontUseCustomDirectoryIcons = 0x00000080,
};

// . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

class FileProperty: Property {
	construct(string_t name);

	string_t bindable autoget property m_value;

	FilePropertyMode autoget property m_mode;
	FilePropertyOptions autoget property m_options;
	string_t autoget property m_fileDialogTitle;
	string_t autoget property m_initialDirectory;
	string_t autoget property m_filter;
}

//..............................................................................

class DictionaryProperty: Property {
	construct(string_t name);

	DictionaryEntry const* bindable autoget property m_value; // onChanged is also fired when contents changes

	string_t autoget property m_propertyDisplayName;
	string_t autoget property m_editDialogTitle;
	string_t autoget property m_keyColumnName;
	string_t autoget property m_valueColumnName;
	string_t autoget property m_placeholderText;
}

//..............................................................................

opaque class PropertyGrid {
	void addProperty(
		Property* prop,
		Property* beforeProp = null
	);

	void removeProperty(Property* prop);

	GroupProperty* createGroupProperty(
		Property* parentProp = null,
		Property* beforeProp = null,
		string_t name,
		string_t toolTip = null
	);

	GroupProperty* createGroupProperty(
		string_t name,
		string_t toolTip = null
	) {
		return createGroupProperty(,, name, toolTip);
	}

	BoolProperty* createBoolProperty(
		Property* parentProp = null,
		Property* beforeProp = null,
		string_t name,
		string_t toolTip = null
	);

	BoolProperty* createBoolProperty(
		string_t name,
		string_t toolTip = null
	) {
		return createBoolProperty(,, name, toolTip);
	}

	IntProperty* createIntProperty(
		Property* parentProp = null,
		Property* beforeProp = null,
		string_t name,
		string_t toolTip = null
	);

	IntProperty* createIntProperty(
		string_t name,
		string_t toolTip = null
	) {
		return createIntProperty(,, name, toolTip);
	}

	StringProperty* createStringProperty(
		Property* parentProp = null,
		Property* beforeProp = null,
		string_t name,
		string_t placeholderText = null,
		string_t toolTip = null
	);

	StringProperty* createStringProperty(
		string_t name,
		string_t placeholderText = null,
		string_t toolTip = null
	) {
		return createStringProperty(,, name, placeholderText, toolTip);
	}

	EnumProperty* createEnumProperty(
		Property* parentProp = null,
		Property* beforeProp = null,
		string_t name,
		string_t toolTip = null,
		EnumPropertyOption const* optionArray,
		size_t count
	);

	EnumProperty* createEnumProperty(
		string_t name,
		string_t toolTip = null,
		EnumPropertyOption const* optionArray,
		size_t count
	) {
		return createEnumProperty(,, name, toolTip, optionArray, count);
	}

	ComboProperty* createComboProperty(
		Property* parentProp = null,
		Property* beforeProp = null,
		string_t name,
		string_t placeholderText,
		string_t toolTip = null,
		EnumPropertyOption const* optionArray = null,
		size_t count = 0
	);

	ComboProperty* createComboProperty(
		string_t name,
		string_t placeholderText = null,
		string_t toolTip = null,
		EnumPropertyOption const* optionArray = null,
		size_t count = 0
	) {
		return createComboProperty(,, name, placeholderText, toolTip, optionArray, count);
	}

	FlagProperty* createFlagProperty(
		Property* parentProp = null,
		Property* beforeProp = null,
		string_t name,
		string_t toolTip = null,
		FlagPropertyOption const* optionArray,
		size_t count
	);

	FlagProperty* createFlagProperty(
		string_t name,
		string_t toolTip = null,
		FlagPropertyOption const* optionArray,
		size_t count
	) {
		return createFlagProperty(,, name, toolTip, optionArray, count);
	}

	ColorProperty* createColorProperty(
		Property* parentProp = null,
		Property* beforeProp = null,
		string_t name,
		string_t toolTip = null
	);

	ColorProperty* createColorProperty(
		string_t name,
		string_t toolTip = null
	) {
		return createColorProperty(,, name, toolTip);
	}

	ActionProperty* createActionProperty(
		Property* parentProp = null,
		Property* beforeProp = null,
		string_t name,
		string_t toolTip = null
	);

	ActionProperty* createActionProperty(
		string_t name,
		string_t toolTip = null
	) {
		return createActionProperty(,, name, toolTip);
	}

	FileProperty* createFileProperty(
		Property* parentProp = null,
		Property* beforeProp = null,
		string_t name,
		string_t toolTip = null
	);

	FileProperty* createFileProperty(
		string_t name,
		string_t toolTip = null
	) {
		return createFileProperty(,, name, toolTip);
	}

	DictionaryProperty* createDictionaryProperty(
		Property* parentProp = null,
		Property* beforeProp = null,
		string_t name,
		string_t toolTip = null
	);

	DictionaryProperty* createDictionaryProperty(
		string_t name,
		string_t toolTip = null
	) {
		return createDictionaryProperty(,, name, toolTip);
	}

	void resizeNameColumnToContents();

protected:
	void finalizeCreateProperty(
		Property* prop,
		Property* parentProp,
		Property* beforeProp,
		string_t toolTip
	);
}

// . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

GroupProperty* PropertyGrid.createGroupProperty(
	Property* parentProp,
	Property* beforeProp,
	string_t name,
	string_t toolTip
) {
	GroupProperty* prop = new GroupProperty(name);
	finalizeCreateProperty(prop, parentProp, beforeProp, toolTip);
	return prop;
}

BoolProperty* PropertyGrid.createBoolProperty(
	Property* parentProp,
	Property* beforeProp,
	string_t name,
	string_t toolTip
) {
	BoolProperty* prop = new BoolProperty(name);
	finalizeCreateProperty(prop, parentProp, beforeProp, toolTip);
	return prop;
}

IntProperty* PropertyGrid.createIntProperty(
	Property* parentProp,
	Property* beforeProp,
	string_t name,
	string_t toolTip
) {
	IntProperty* prop = new IntProperty(name);
	finalizeCreateProperty(prop, parentProp, beforeProp, toolTip);
	return prop;
}

StringProperty* PropertyGrid.createStringProperty(
	Property* parentProp,
	Property* beforeProp,
	string_t name,
	string_t placeholderText,
	string_t toolTip
) {
	StringProperty* prop = new StringProperty(name);
	prop.m_placeholderText = placeholderText;
	finalizeCreateProperty(prop, parentProp, beforeProp, toolTip);
	return prop;
}

EnumProperty* PropertyGrid.createEnumProperty(
	Property* parentProp,
	Property* beforeProp,
	string_t name,
	string_t toolTip,
	EnumPropertyOption const* optionArray,
	size_t count
) {
	EnumProperty* prop = new EnumProperty(name);
	prop.setOptions(optionArray, count);
	finalizeCreateProperty(prop, parentProp, beforeProp, toolTip);
	return prop;
}

ComboProperty* PropertyGrid.createComboProperty(
	Property* parentProp,
	Property* beforeProp,
	string_t name,
	string_t placeholderText,
	string_t toolTip,
	EnumPropertyOption const* optionArray,
	size_t count
) {
	ComboProperty* prop = new ComboProperty(name);
	prop.m_placeholderText = placeholderText;

	if (count)
		prop.setOptions(optionArray, count);

	finalizeCreateProperty(prop, parentProp, beforeProp, toolTip);
	return prop;
}

FlagProperty* PropertyGrid.createFlagProperty(
	Property* parentProp,
	Property* beforeProp,
	string_t name,
	string_t toolTip,
	FlagPropertyOption const* optionArray,
	size_t count
) {
	FlagProperty* prop = new FlagProperty(name);
	prop.setOptions(optionArray, count);
	finalizeCreateProperty(prop, parentProp, beforeProp, toolTip);
	return prop;
}

ColorProperty* PropertyGrid.createColorProperty(
	Property* parentProp,
	Property* beforeProp,
	string_t name,
	string_t toolTip
) {
	ColorProperty* prop = new ColorProperty(name);
	finalizeCreateProperty(prop, parentProp, beforeProp, toolTip);
	return prop;
}

ActionProperty* PropertyGrid.createActionProperty(
	Property* parentProp,
	Property* beforeProp,
	string_t name,
	string_t toolTip
) {
	ActionProperty* prop = new ActionProperty(name);
	finalizeCreateProperty(prop, parentProp, beforeProp, toolTip);
	return prop;
}

FileProperty* PropertyGrid.createFileProperty(
	Property* parentProp,
	Property* beforeProp,
	string_t name,
	string_t toolTip
) {
	FileProperty* prop = new FileProperty(name);
	finalizeCreateProperty(prop, parentProp, beforeProp, toolTip);
	return prop;
}

DictionaryProperty* PropertyGrid.createDictionaryProperty(
	Property* parentProp,
	Property* beforeProp,
	string_t name,
	string_t toolTip
) {
	DictionaryProperty* prop = new DictionaryProperty(name);
	finalizeCreateProperty(prop, parentProp, beforeProp, toolTip);
	return prop;
}

void PropertyGrid.finalizeCreateProperty(
	Property* prop,
	Property* parentProp,
	Property* beforeProp,
	string_t toolTip
) {
	prop.m_toolTip = toolTip;

	parentProp ?
		parentProp.addChildProperty(prop, beforeProp) :
		addProperty(prop, beforeProp);
}

//..............................................................................

//! @}

} // namespace ui
