Ext.define("Ext.ux.gallery.Media", {

	extend: "Ext.panel.Panel",

	alias: ["widget.mediagallery"],

	mixins: {
		componentController: "Ext.ux.util.ComponentController"
	},

	refs: [
		{
			ref: "dropbox",
			selector: "gallerydropbox"
		},
		{
			ref: "grid",
			selector: "gallerymediagrid"
		},
		{
			ref: "toolbar",
			selector: "#gallerytoolbar"
		}
	],

	border: true,
	config: {
		galleryGrid: null,
		store: null,
		addButton: null,
		pageSize: 0,
		path: "",
		maxItems: -1,
		layoutConfig: null,
		linkConfig: null,
		editorConfig: null,
		extensions: "*",
		dragText: "",
		dropText: "",
		confirmRemoveRowText: "",
		confirmRemoveRowsText: "",
		ignoreStaticDir: false,
		itemCreateText: "",
		itemEditText: "",
		itemRemoveText: "",
		itemCreateTitle: "",
		itemEditTitle: "",
		actionColumns: null,
		dropzone: null,
		contextMenu: null,
		fields: null,
		uploading: false,
		isValueInit: false,
		mediaType: ""
	},

	initComponent: function () {

		var i_self = this;
		var o_config = i_self.initialConfig;

		// Apply non-primitive configurations defaults
		Ext.apply(i_self, {
			linkConfig: o_config.linkConfig || i_self.linkConfig,
			layoutConfig: o_config.layoutConfig || i_self.layoutConfig,
			actionColumns: o_config.actionColumns || {},
			ignoreStaticDir: o_config.ignoreStaticDir || i_self.ignoreStaticDir,
			dragText: o_config.dragText || {
				en: "Drag and drop a row to reorder",
				da: "Slip for at re-arrangere rækkefølge"
			},
			dropText: o_config.dropText || {
				en: "Drag-and-drop your images here",
				da: "Træk-og-slip dine billeder her"
			},
			confirmRemoveRowText: o_config.confirmRemoveRowText || {
				da: "Ønsker du virkelig at fjerne denne række?",
				en: "Do you really wish to remove this row?"
			},
			confirmRemoveRowsText: o_config.confirmRemoveRowsText || {
				da: "Ønsker du virkelig at fjerne de valgte rækker?",
				en: "Do you really wish to remove the selected rows?"
			},
			itemCreateTitle: o_config.itemCreateTitle || {
				da: "Tilføj nyt emne",
				en: "Add new item"
			},
			itemEditTitle: o_config.itemEditTitle || {
				da: "Rediger",
				en: "Edit"
			},
			itemCreateText: o_config.itemCreateText || {
				da: "Tilføj",
				en: "Add"
			},
			itemEditText: o_config.itemEditText || {
				da: "Rediger",
				en: "Edit"
			},
			itemRemoveText: o_config.itemRemoveText || {
				da: "Fjern",
				en: "Remove"
			},
			bodyStyle: {
				"background-color": "white"
			},
			editorConfig: {
				renderTo: Ext.getBody(),
				width: "60%",
				height: "60%",
				autoShow: true,
				linkConfig: i_self.linkConfig,
				layoutConfig: i_self.layoutConfig,
				path: i_self.path,
				extensions: i_self.extensions,
				ignorestaticdir: i_self.ignoreStaticDir,
				modal: false,
				mediaType: i_self.getMediaType(),
				listeners: {
					update: {
						fn: i_self.updateData,
						scope: i_self
					},
					create: {
						fn: i_self.createData,
						scope: i_self
					},
					destroy: {
						fn: i_self.refocusGrid,
						scope: i_self
					}
				}
			}
		});

		// Initialize the component controller utility mixin
		i_self.initComponentController();

		// Call the parent class for the class chain
		i_self.callParent(arguments);

		i_self.addStore();

		// Add the needed store and components
		i_self.addComponents();

		// Add the control object for event handling
		i_self.addControls();

		i_self.initValue();

		return i_self;
	},

	initValue: function () {

		var i_self = this;
		var value = i_self.value;

		i_self.setValue(value);
		i_self.originalValue = value;
		i_self.isValueInit = true;

		return i_self;
	},

	// Add the store, components and the control objects for components
	addStore: function () {

		var i_self = this;
		var o_actionColumns = i_self.actionColumns;

		var a_fields = [
			{ name: "RELCHDTKN", type: "int" },
			{ name: "_id", type: "string" },
			{ name: "url", type: "auto", defaultValue: "" },
			{ name: "name", type: "string", defaultValue: "" },
			{ name: "sequence", type: "int" },
			{ name: "layout", type: "auto", defaultValue: "" },
			{ name: "link", type: "auto", defaultValue: "" },
			{ name: "title", type: "auto", defaultValue: "" },
			{ name: "caption", type: "auto", defaultValue: "" },
			{ name: "type", type: "string", defaultValue: "image" },
			{ name: "target", type: "string", defaultValue: "" }
		];

		i_self.fields = a_fields;

		// Add the action columns (all boolean)
		Ext.Object.each(o_actionColumns, function (s_key, o_config) {
			a_fields.push({
				name: s_key,
				type: "boolean",
				defaultValue: false
			});
		});

		var i_store = Ext.create("Ext.data.Store", {
			fields: a_fields,
			proxy: {
				type: "memory",
				reader: {
					type: "json",
					rootProperty: "images"
				}
			}
		});

		i_self.setStore(i_store);

		return i_self;
	},

	addComponents: function () {

		var i_self = this;
		var o_initial = i_self.initialConfig;
		var i_store = i_self.getStore();
		

		var i_galleryGrid = Ext.widget("gallerymediagrid", {
			store: i_store,
			multiSelect: true,
			linkConfig: i_self.linkConfig,
			actionColumns: i_self.actionColumns,
			viewConfig: {
				plugins: [
					{
						ptype: "gridviewdragdrop",
						dragText: ip2.i18n(o_initial.dragText || i_self.dragText)
					}
				],
				listeners: {
					beforedrop: {
						fn: function(node, data, overRecord, position) {
							var i_store = data.view.ownerCt.getStore();
							i_store.fireEvent("beforereorder", i_store);
						}
					},
					drop: {
						fn: function(node, data, overRecord, position) {
							var i_store = data.view.ownerCt.getStore();
							var a_data = i_store.data.items;
							var n_index = 0;
							var b_found = false;
							Ext.Array.each(a_data, function(i_record) {
								if (i_record.get("RELCHDTKN") == data.records[0].get("RELCHDTKN")) {
									b_found = true;
								}
								if (!b_found) {
									n_index++;
								}
							});
							if (!b_found) {
								n_index = 0;
							}
							i_store.fireEvent("reorder", i_store, data.records, n_index);
						}
					}
				}
			},
			listeners: {
				afterrender: {
					fn: function(i_grid) {

						var i_store = i_grid.getStore();

						var a_records = i_store.getRange();

						i_galleryGrid[Ext.isEmpty(a_records) ? "hide" : "show"]();
					}
				}
			}
		});

		i_store.on({
			datachanged: {
				fn: function(i_store) {

					var a_records = i_store.getRange();

					i_galleryGrid[Ext.isEmpty(a_records) ? "hide" : "show"]();
				}
			}
		});

		var i_addButton = Ext.widget("button", {
			itemId: "createButton",
			text: ip2.i18n(i_self.itemCreateText),
			handler: function () {
				i_self.onCollectionItemAdd();
			}
		});

		i_self.add([
			{
				xtype: "container",
				layout: {
					type: "hbox",
					align: "center"
				},
				style: {
					"background-color": "white",
					"padding": "7px"
				},
				defaults: {
					margin: "0px 10px 0px 0px"
				},
				items: [
					i_addButton,
					{
						xtype: "gallerydropbox",
						extensions: o_initial.extensions || i_self.extensions,
						dropText: o_initial.dropText || i_self.dropText,
						flex: 1,
						padding: 2,
						maxItems: i_self.maxItems,
						margin: "0px 0px 0px 0px"
					}
				]
			},
			i_galleryGrid
		]);

		i_self.contextMenu = Ext.widget("menu", {
			renderTo: Ext.getBody(),
			items: [
				{
					xtype: "menuitem",
					itemId: "editButton",
					text: ip2.i18n(i_self.itemEditText),
					iconCls: "pf-edit"
				},
				{
					xtype: "menuitem",
					itemId: "removeButton",
					text: ip2.i18n(i_self.itemRemoveText),
					iconCls: "pf-delete"
				},
				{
					xtype: "menuitem",
					itemId: "previewButton",
					text: ip2.i18n({
						da: "Preview",
						en: "Preview"
					}),
					iconCls: "pf-eye"
				}
			]
		});

		i_self.setGalleryGrid(i_galleryGrid);
		i_self.setAddButton(i_addButton);

		return i_self;
	},

	addControls: function () {

		var i_self = this;

		i_self.on({
			afterrender: {
				fn: function (i_self) {
					i_self.syncButtons();
				},
				single: true
			},
			create: {
				fn: function (i_self) {
					i_self.syncButtons();
				}
			},
			update: {
				fn: function (i_self) {
					i_self.syncButtons();
				}
			},
			remove: {
				fn: function (i_self) {
					i_self.checkAutoSelectColumns();
					i_self.syncButtons();
				}
			},
			empty: {
				fn: function (i_self) {
					i_self.syncButtons();
				}
			}
		});

		i_self.control({
			"grid": {
				itemedit: i_self.onCollectionItemEdit,
				itemdblclick: i_self.onCollectionItemEdit,
				itemremove: i_self.onCollectionItemRemove,
				deletekey: i_self.onCollectionItemRemove,
				itemcontextmenu: i_self.onCollectionContext,
				scope: i_self
			},
			"dropbox": {
				drop: i_self.onDrop,
				beforedrop: i_self.onBeforeDrop,
				dragenter: i_self.onDragEnter
			}
		});

		return i_self;
	},

	openItemEditor: function (i_record) {

		var i_self = this;
		var o_defaults = i_self.editorConfig;

		var o_config = {
			title: i_record ?
				[
					ip2.i18n(i_self.itemEditTitle),
					i_record.get("url")
				].join(" ")
				:
				ip2.i18n(i_self.itemCreateTitle),
			record: i_record,
			ignoreStaticDir: i_self.ignoreStaticDir,
			type: i_record ? i_record.get("type") : "image",
			activeTab: "mediaproperties"
		};

		Ext.apply(o_config, o_defaults);

		var i_window = Ext.widget("gallerymediaeditor", o_config);

		i_window.on("aftersave", function(item, record) {
			i_self.createData([record], true);
		});

		return i_self;
	},

	// Component control event handling methods
	onDragEnter: function (i_dropbox, o_event) {

		var i_self = this;

		var i_plugin = i_dropbox.getDDPlugin();
		var b_valid = i_self.validateDrop(o_event);

		if (!b_valid) {
			i_dropbox.addCls(i_plugin.failureCls);
		}
	},

	onBeforeDrop: function (i_dropbox, i_files, o_event) {

		var i_self = this;
		var b_valid = i_self.validateDrop(o_event);

		return b_valid;
	},

	onDrop: function (i_dropbox, i_files) {

		var i_self = this;
		var i_store = i_self.getStore();
		var i_el = i_self.getEl();
		var a_concat = [];
		var s_path = "";

		var s_preset = ip2.preset.staticPath || "pp-static";

		if (i_self.ignoreStaticDir) {
			s_path = i_self.path;
		}
		else {
			s_path = ip2.cleanPath([s_preset, i_self.path].join("/"));
		}

		var msg = ip2.i18n({
			da: "Kontrolerer filer....",
			en: "Checking files..."
		});
		i_el.mask(msg);

		Ext.ux.file.util.Handler.checkFiles(s_path, i_files, function(o_result) {

			i_el.unmask();
			var a_update = o_result.update;
			var a_create = o_result.create;
			var b_update = false;
			var b_cancel = false;
			var b_create = false;
			var msg;

			if (a_update.length > 0) {
				b_update = true;
				var b_override = false;
				var b_rename = false;
				Ext.ux.file.util.Handler.getUIConflickWindow(
					i_el.el,
					i_self,
					s_path,
					a_update,
					function(cancel, a_override, a_rename) {

						b_cancel = cancel;
						if (a_override.length > 0) {
							b_override = true;
							msg = ip2.i18n({
								da: "Overskriver filer....",
								en: "Overriding files..."
							});
							i_el.mask(msg);
							var a_files = [];
							Ext.Array.each(a_override, function(o_file) {
								a_files.push(o_file.file);
							});
							if (Ext.ux.file.util.Handler.hasFileManager()) {
								var a_names = [];
								Ext.Array.each(a_files, function(o_file) {
									a_names.push(o_file.name);
								});
								var s_url = path = ip2.cleanPath(s_path) + "/";
								Ext.ux.file.util.Handler.getRecordsByName(s_url, a_names, function(a_records) {
									if (a_records.length === 0) {
										Ext.ux.file.util.Handler.createRecords(s_path, a_files, false, function(a_records) {
											a_concat = a_concat.concat(a_files);
											b_override = false;
											if (!b_rename && !b_create) {
												i_el.unmask();
												i_self.createFromFiles(a_concat, s_path, true);
											}
										});
									}
									else {
										var a_create = [];
										Ext.Array.each(a_files, function(o_file) {
											var b_found = false;
											Ext.Array.each(a_names, function(s_name) {
												if (s_name == o_file.name) {
													b_found = true;
												}
											});
											if (!b_found) {
												a_create.push(o_file);
											}
										});
										if (a_create.length > 0) {
											Ext.ux.file.util.Handler.createRecords(s_path, a_create, false, function(a_records) {
												a_concat = a_concat.concat(a_files);
												b_override = false;
												if (!b_rename && !b_create) {
													i_el.unmask();
													i_self.createFromFiles(a_concat, s_path, true);
												}
											});
										}
										else {
											a_concat = a_concat.concat(a_files);
											b_override = false;
											if (!b_rename && !b_create) {
												i_el.unmask();
												i_self.createFromFiles(a_concat, s_path, true);
											}
										}
									}
								});
							}
							else {
								Ext.ux.file.util.Handler.uploadFiles(s_path, a_files, false, function(a_records) {
									a_concat = a_concat.concat(a_files);
									b_override = false;
									if (!b_rename && !b_create) {
										i_el.unmask();
										i_self.createFromFiles(a_concat, s_path, true);
									}
								});
							}
						}
						if (a_rename.length > 0) {
							b_rename = true;
							if (!b_override) {
								msg = ip2.i18n({
									da: "Opretter filer....",
									en: "Creating files..."
								});
								i_el.mask(msg);
							}
							if (Ext.ux.file.util.Handler.hasFileManager()) {
								Ext.ux.file.util.Handler.createRecords(s_path, a_rename, true, function(a_records) {
									a_concat = a_concat.concat(a_rename);
									b_rename = false;
									if (!b_override && !b_create) {
										i_el.unmask();
										i_self.createFromFiles(a_concat, s_path, true);
									}
								});
							}
							else {
								Ext.ux.file.util.Handler.uploadFiles(s_path, a_rename, true, function(a_records) {
									a_concat = a_concat.concat(a_rename);
									b_rename = false;
									if (!b_override && !b_create) {
										i_el.unmask();
										i_self.createFromFiles(a_concat, s_path, true);
									}
								});
							}
						}
						if (!b_override && !b_rename) {
							if (!b_create) {
								i_el.unmask();
								i_self.createFromFiles(a_concat, s_path, true);
							}
							else {
								msg = ip2.i18n({
									da: "Opretter filer....",
									en: "Creating files..."
								});
								i_el.mask(msg);
							}
						}
					}, false);
			}
			if (a_create.length > 0) {
				b_create = true;
				if (!b_update) {
					i_el.unmask();
					msg = ip2.i18n({
						da: "Opretter filer....",
						en: "Creating files..."
					});
					i_el.mask(msg);
				}
				if (Ext.ux.file.util.Handler.hasFileManager()) {
					Ext.ux.file.util.Handler.createRecords(s_path, a_create, false, function(a_records) {
						a_concat = a_concat.concat(a_create);
						b_create = false;
						if (!b_update || b_cancel) {
							i_el.unmask();
							i_self.createFromFiles(a_concat, s_path, true);
						}
					});
				}
				else {
					Ext.ux.file.util.Handler.uploadFiles(s_path, a_create, false, function(a_records) {
						a_concat = a_concat.concat(a_create);
						b_create = false;
						if (!b_update || b_cancel) {
							i_el.unmask();
							i_self.createFromFiles(a_concat, s_path, true);
						}
					});
				}
			}
		});
	},

	createFromFiles: function(a_files, s_path, b_append) {

		var i_self = this;
		var a_result = [];
		Ext.Array.each(a_files, function(i_file) {
			var o_file = i_file.file || i_file;
			var s_name = i_file.suggestedName || o_file.name;
			var s_url = [s_path, s_name].join("/");
			var o_record = {
				name: s_name,
				url: s_url
			};
			a_result.push(o_record);
		});
		i_self.createData(a_result, b_append);
	},

	onCollectionItemAdd: function () {

		var i_self = this;
		var i_grid = i_self.getGrid();
		var i_store = i_grid.getStore();
		var i_model = i_store.model.create();
		i_self.openItemEditor(i_model);

		return i_self;
	},

	onCollectionItemEdit: function (n_row, i_record) {

		var i_self = this;
		var i_store = i_self.getStore();

		// Delegator is either a doubleclick or itemcontextmenu handler
		// So we get the record by row number
		if (Ext.isNumber(n_row)) {
			i_record = i_store.getAt(n_row);
		}

		i_self.openItemEditor(i_record);

		return i_self;
	},

	onCollectionItemRemove: function (toRemove) {

		var i_self = this;
		var i_store = i_self.getStore();
		var s_message;

		// If toRemove is a number, then it is the row to remove
		if (Ext.isNumber(toRemove)) {

			s_message = ip2.i18n(i_self.confirmRemoveRowText);

			i_self.throwMessage(s_message, function () {
				i_self.removeData(toRemove);
			});
		}

		if (!toRemove) {

			var i_grid = i_self.getGrid();
			var a_selected = i_grid.getSelectionModel().getSelection();
			var n_selected = a_selected.length;

			if (n_selected) {

				s_message = n_selected > 1 ? i_self.confirmRemoveRowsText : i_self.confirmRemoveRowText;
				s_message = ip2.i18n(s_message);

				i_self.throwMessage(s_message, function () {
					i_self.removeData(a_selected);
				});
			}
		}
	},

	onCollectionContext: function (i_media, i_record, i_item, n_index, o_event) {

		o_event.preventDefault();

		var i_self = this;
		var i_store = i_self.getStore();
		var i_menu = i_self.contextMenu;
		var b_allowAdd = i_self.allowAdd();
		var a_xy = o_event.getXY();

		var i_remove = i_menu.items.get("removeButton");
		var i_edit = i_menu.items.get("editButton");
		var i_preview = i_menu.items.get("previewButton");

		if (i_remove) {
			i_remove.handler = function () {
				i_self.onCollectionItemRemove();
			};
		}

		if (i_edit) {
			i_edit.handler = function () {
				i_self.onCollectionItemEdit(n_index);
			};
		}

		if (i_preview) {
			i_preview.handler = function () {

				var o_size = ip2.getWindowSize();

				var s_extension = i_record.get("name") || i_record.get("url");

				s_extension = s_extension.split(".").pop();

				var a_extension_image = ["jpg","jpeg","png","gif", "bmp"];

				s_extension = s_extension.toLowerCase();

				var i_window = Ext.widget("window", {
					layout: "fit",
					title: "Preview - " + (i_record.get("name") || i_record.get("title")),
					width: o_size.width * 0.6,
					height: o_size.height * 0.8,
					listeners: {
						afterrender: {
							fn: function() {
								Ext.GlobalEvents.fireEvent("applyContextMenu");
							}
						},
						destroy: {
							fn: function() {

								var i_globalWindow = Ext.get(window.document);
								i_globalWindow.events.contextmenu.clearListeners();

								Ext.GlobalEvents.fireEvent("removeContextMenu");
							}
						}
					}
				});

				var a_items = [];

				if (Ext.Array.contains(a_extension_image, s_extension)) {

					var i_canvas = Ext.widget("component", {
						autoEl: {
							tag: "canvas"
						}
					});

					var i_container = Ext.widget("container", {
						itemId: "canvas-container",
						items: [
							i_canvas
						],
					});

					var i_image = new Image();

					i_image.onload = function() {
						i_container.fireEvent("resize", i_container, i_container.getWidth(), i_container.getHeight());
					};

					i_container.on({
						resize: {
							fn: function(i_wrapper) {

								var i_canvasEl = i_canvas.getEl();
								var i_canvasDom = i_canvasEl.dom;
								var n_width = i_wrapper.getWidth();
								var n_height = i_wrapper.getHeight();

								var i_context = i_canvasDom.getContext("2d");

								i_context.clearRect(0, 0, n_width, n_height);

								i_canvasDom.width = n_width;
								i_canvasDom.height = n_height;

								i_context.drawImage(i_image, 10, 10, n_width - 20, n_height -20);
								
							},
							buffer: 100
						}
					});

					a_items.push(i_container);

					i_image.src = i_record.get("url");
				}
				else {
					var i_iframe = Ext.widget("containeriframe", {
						src: i_record.get("url")
					});
					a_items.push(i_iframe);
				}

				i_window.add(a_items);

				i_window.show();
			};
		}

		i_menu.showAt(a_xy[0], a_xy[1]);
	},

	createData: function (data, b_append) {

		var i_self = this;
		var i_store = i_self.getStore();
		var i_model = i_store.getModel();
		var a_data = Ext.Array.from(data);

		// If we have nothing in store, and we have actionColumns applied
		// then we need to apply default autoSelect values to first dataset in a_data
		var n_store = i_store.getCount();
		var o_actionColumns = i_self.actionColumns;

		// Check autoSelect defaults for row context groups in actionColumns
		Ext.Array.each(a_data, function (o_data, n_index) {

			// Get row context based default values for autoSelect
			var o_defaults = i_self.getAutoSelectDefaults("row");

			// If store is empty then we need to apply column context defaults
			if (!n_store && n_index === 0 && i_self.isValueInit) {
				var o_columnDefaults = i_self.getAutoSelectDefaults("column");
				Ext.apply(o_defaults, o_columnDefaults);
			}

			if (o_data.isModel) {
				if (o_data.phantom !== null && o_data.modified !== null) {
					o_data.set(o_defaults);
				}
			}
			else {
				Ext.apply(o_data, o_defaults);
			}
		});

		i_store.loadData(a_data, b_append);

		i_self.fireEvent("create", i_self);

		return i_self;
	},

	updateData: function (data, i_record) {

		var i_self = this;
		var i_store = i_self.getStore();
		var a_data = Ext.Array.from(data);
		var a_records = [];

		Ext.Array.each(a_data, function (o_data) {

			if (!i_record) {
				i_record = i_self.findRecordByData(o_data);
			}

			if (i_record) {

				a_records.push(i_record);

				i_record.set(o_data);

				// Only refresh the row we messed with
				var n_index = i_store.indexOf(i_record);
				if (n_index > -1) {
					i_self.getGrid().getView().refreshNode(n_index);
				}
			}
		});

		return i_self;
	},

	removeData: function (toRemove) {

		// toRemove can be one of the following
		// - record
		// - object/values
		// - index (in store)
		var i_self = this;
		var i_store = i_self.getStore();
		var a_remove = Ext.Array.from(toRemove);
		var a_records = [];

		Ext.Array.each(a_remove, function (item) {

			var i_record;

			if (Ext.isNumber(item)) {
				i_record = i_store.getAt(item);
			}
			if (Ext.isObject(item)) {

				// Is a record?
				if (item.store && item.store.model && item instanceof item.store.model) {
					i_record = item;
				}
				else {
					i_record = i_self.findRecordByData(item);
				}
			}

			a_records.push(i_record);
		});

		// Our records to remove array is ready
		i_store.remove(a_records);
		if (i_store.getData().length === 0) {
			i_self.fireEvent("empty", i_self);
		}
		else {
			i_self.fireEvent("datachanged", i_self);
		}
	},

	emptyData: function () {

		var i_self = this;
		var i_store = i_self.getStore();

		i_store.removeAll();

		i_self.fireEvent("empty", i_self);

		return i_self;
	},

	loadData: function (data, b_append) {

		var i_self = this;
		var i_store = i_self.getStore();
		var a_data = Ext.Array.from(data);
		i_store.removeAll(true);
		i_store.loadData(a_data);
		return i_self;
	},

	createFileData: function (o_file) {

		var i_self = this;
		var s_path = i_self.path;
		var s_name = o_file.name;

		var s_url = [s_path, s_name].join(""/"");

		s_url = ip2.cleanPath(s_url);

		return {
			name: s_name,
			url: s_url
		};
	},

	humanFileSize: function (bytes) {
		return ip2.humanFileSize(bytes);
	},

	syncButtons: function () {

		var i_self = this;

		i_self.syncAddButton();

		return i_self;
	},
	syncAddButton: function () {

		var i_self = this;
		var n_max = i_self.maxItems;
		var i_button = i_self.getAddButton();
		var value = i_self.getValue();

		if (n_max === 0) {
			i_button.disable();
		}
		else if (n_max == 1 && Ext.Object.getSize(value)) {
			i_button.disable();
		}
		else if (value && n_max > value.length) {
			i_button.disable();
		}
		else {
			i_button.enable();
		}

		return i_self;
	},

	syncRemoveButton: function () {

		var i_self = this;
		var i_toolbar = i_self.getToolbar();
		var i_button = i_toolbar.down("#removeButton");
		var n_max = i_self.maxItems;
		var value = i_self.getValue();

		if (n_max === 0) {
			i_button.disable();
		}
		else if (Ext.Object.getSize(value) || (Ext.isArray(value) && value.length)) {
			i_button.enable();
		}
		else {
			i_button.disable();
		}

		return i_self;
	},

	// Value handling
	getValue: function () {

		var i_self = this;
		var i_store = i_self.getStore();
		var b_single = (i_self.maxItems == 1) ? true : false;
		var a_value = [];
		var o_value = {};
		var a_records = i_store.data.items.slice(0);

		Ext.Array.each(a_records, function(i_record, n_index) {
			var o_data = ip2.clone(i_record.data);

			if (b_single) {
				o_value = o_data;
			}
			else {
				o_data.sequence = n_index;

				a_value.push(o_data);
			}
		});

		if (a_value.length && b_single) {
			o_value = value.length ? a_value[0] : {};
		}

		if (b_single) {
			o_value = trim(o_value);
		}
		else {
			Ext.Array.each(a_value, function (o_value, n_index) {
				a_value[n_index] = trim(o_value);
			});
		}

		function trim (o_value) {
			var o_return = {};
			Ext.Object.each(o_value, function (s_key, value) {
				if (value === null) {
					o_return[s_key] = "";
				}
				else {
					o_return[s_key] = value;
				}
			});
			return o_return;
		}

		return b_single ? o_value : a_value;
	},

	setValue: function (value) {

		var i_self = this;
		var i_store = i_self.getStore();

		var a_values = Ext.Array.from(value);

		if (Ext.isString(value)) {

			a_values = Ext.decode(value, true) || [];
		}

		if (a_values.length > 0) {
			i_self.loadData(a_values);
		}
		else {
			i_self.emptyData();
		}

		i_self.value = a_values;

		return i_self;
	},

	// Utility methods
	refocusGrid: function () {
		var i_self = this;
		var i_grid = i_self.getGrid();

		// Make sure the previously selected rows are once again selected
		var a_selected = i_grid.getSelectionModel().getSelection();

		i_grid.getView().focus();
		i_grid.getSelectionModel().select(a_selected);

		return i_self;
	},

	getAutoSelectDefaults: function (s_context) {

		var i_self = this;
		var o_columns = i_self.actionColumns || {};

		var o_defaults = {};

		// AutoSelect columns come in 2 contexts, column or row
		// - Column context ('column') = radio or radiocheckbox
		// - Row context ('row') = radio, radiocheckbox or checkbox
		Ext.Object.each(o_columns, function (s_key, o_config) {

			var b_select = o_config.autoSelect;

			if (b_select && o_config.context == s_context) {
				o_defaults[s_key] = b_select;
			}
		});

		return o_defaults;
	},

	checkAutoSelectColumns: function () {

		var i_self = this;
		var i_store = i_self.getStore();
		var o_columns = i_self.actionColumns;

		if (o_columns) {

			var o_map = {};

			// Create the initial map to check for flags
			Ext.Object.each(o_columns, function (s_key, o_column) {
				if (o_column.autoSelect) {
					o_map[s_key] = false;
				}
			});

			// Check each record and set flag to true if an value was found
			i_store.each(function (i_record) {
				Ext.Object.each(o_map, function (s_key, value) {
					if (i_record.get(s_key)) {
						o_map[s_key] = true;
					}
				});
			});

			// Check first record in store - if value is false, then check
			// first record
			Ext.Object.each(o_map, function (s_key, value) {
				if (!value) {
					var i_record = i_store.getAt(0);
					if (i_record) {
						i_record.set(s_key, true);
					}
				}
			});
		}

		return i_self;
	},

	validateDrop: function (o_event) {

		var i_self = this;
		var b_valid = true;

		var o_datatransfer = o_event.dataTransfer;
		var a_files = o_datatransfer.items || o_datatransfer.files;

		var n_transfer = a_files.length;
		var n_max = i_self.maxItems;
		var n_count = i_self.getStore().getCount();

		// Only check conditions if this is not a limitless list
		if (n_max != -1) {
			// Do not allow if more files are being uploaded than list holds
			if (n_count + n_transfer > n_max) {
				b_valid = false;
			}
		}

		return b_valid;
	},

	findRecordByData: function (o_data) {

		var i_self = this;
		var i_store = i_self.getStore();
		var i_found;

		i_store.data.each(function (i_record) {

			if (i_record.get("name") == o_data.name) {
				i_found = i_record;
			}
		});

		return i_found;
	},

	hasRecord: function (o_data) {

		var i_self = this;
		var i_store = i_self.getStore();
		var b_hasRecord = false;

		i_store.data.each(function (i_record) {

			if (i_record.get("name") == o_data.name) {
				b_hasRecord = true;
			}
		});

		return b_hasRecord;
	},

	allowAdd: function () {

		var i_self = this;
		var b_allow = true;

		var n_max = i_self.maxItems;
		var n_count = i_self.getStore().getCount();

		if (n_max != -1 && n_count >= n_max) {
			b_allow = false;
		}

		return b_allow;
	},

	// Message handling
	throwMessage: function (o_message, f_confirm, f_cancel) {

		f_confirm = f_confirm || Ext.emptyFn;
		f_cancel = f_cancel || Ext.emptyFn;

		var o_config = {
			message: ip2.i18n(o_message),
			width: 400,
			yesText: ip2.i18n({
				da: "Ja",
				en: "Yes"
			}),
			noText: ip2.i18n({
				da: "Nej",
				en: "No"
			}),
			yesFn: function () {
				f_confirm();
			},
			noFn: function () {
				f_cancel();
			}
		};

		ip2.messageBox(o_config);
	},

	isDirty: function () {

		var i_self = this;
		var i_grid = i_self.getGrid();
		var b_dirty = i_grid.isDirty();

		return b_dirty;
	},

	changeLanguage: function(s_language) {
		var i_self = this;
		var i_grid = i_self.getGrid();
		i_grid.changeLanguage(s_language);
	}
});
