﻿// Ensure Common namespace
UserAdmin.Common = UserAdmin.Common || {};

(function(UA) {    
    UA.Common.Form = function(options) {
        var _self = {},
            _options = $.extend({
                id: 'ua-form-generic',
                target: 'body',
                url: '',
                passwordUrl: '',
                
                title: 'Form', 
                openOn: '',
                saved: null,
                dialog: true,
                
                groups: {},
                fields: [],
                fieldsUrl: null,
                fieldsContext: 'all',
                lists: {},
                simpleForms: {},
                lazyLoaders: {},
                buttons: { 'Save':function() {} },
                saveButton: 'Save',
                clearButton: 'Clear'
            }, options),
            _manager,
            _dataObj = null,
            _lazyLoadList = {};
        var _passwordForm;
        var _fieldsLoaded = false, _onFieldsLoaded = null;
        
		var $fieldsets = {};
        var $container, $messages;
        
        // Private methods
		function _getPKValue() {
		    var pkMapping = null, pkVal;
		    if(_dataObj) {
		        $.each(_options.fields, function(i, field) {
		            if(field.primaryKey) {
		                pkMapping = field.property;
		                return false;
		            }
		        });
		        if(pkMapping) {
		            pkVal = _dataObj[pkMapping];
		        }
		    }
		    return pkVal;
		}
		
        function _buildControl($li, field, id) {
			var width = '';
			if(field.width) {
				switch(field.width) {
					case 'big': width = '90%'; break;
					case 'medium': width = '70%'; break;
					case 'small': width = '40%'; break;
					case 'tiny': width = '20%'; break;
					default: width = field.width; break;
				}
			}
			var css = {};
			if(width) {
				css.width = width;
			}
			var html, $list;
			var required = field.required ? ' rel="required"' : '';
			
			if(field.disabled) {
			    $('<span id="' + id + '"></span>').appendTo($('.ua-form-ctrl', $li));
			} else {
			    switch(field.type) {
				    case 'date':
					    $('<input type="text" id="' + id + '" class="ui-state-default"' + required + ' />')
						    .css(css)
						    .appendTo($('.ua-form-ctrl', $li))
						    .datepicker();
					    break;
				    case 'singlelist':
			            html = '<select id="' + id + '" class="ui-state-default"' + required + '></select>';
				        $list = $(html).css(css).appendTo($('.ua-form-ctrl', $li));
				        if(field.addform && _options.simpleForms[field.addform]) {
				            var addhtml = '<a href="javascript:void(0)" title="Add New ' + field.label + '" class="ua-form-addsimple">Add new ' + field.label + '</a>';
				            $(addhtml).css(css).appendTo($('.ua-form-ctrl', $li)).click(function() {
				                _options.simpleForms[field.addform].show();
				            });
				        }
				        var listLoad = function() {
				            var items = _options.lists[field.list].list;
				            var itemsHtml = '<option value="">Choose ' + field.label + '...</option>';
				            $.each(items, function(key, val) {
				                var k = key;
				                if(typeof key === 'number') {
				                    k = val;
				                }
				                itemsHtml += '<option value="' + k + '">' + val + '</option>';
				            });
					        $list.empty().append(itemsHtml);
				        };
					    if(field.list && _options.lists[field.list] && _options.lists[field.list].list) {
					        listLoad();
					    } else if(field.list) {
					        _lazyLoadList[field.list] = listLoad;
					    }
				        break;
				    case 'multilist':
					    var listRequired = field.required ? ' ua-form-list-required' : '';
					    html = '<ul id="' + id + '" class="ui-state-default' + listRequired + '"></ul>';
					    $list = $(html).css(css).appendTo($('.ua-form-ctrl', $li));
				        // define a function that can either be run now or later
				        var ml_listLoad = function() {
				            var items = _options.lists[field.list].list;
				            var itemsHtml = '';
					        $.each(items, function(key, val) {
						        var itemid = id + '-' + key;
						        itemsHtml += ['<li>', 
								        '<input type="checkbox" id="',itemid,'" rel="',key,'" class="ui-state-default" /> ', 
								        '<label for="',itemid,'">',val,'</label>',
							        '</li>'].join('');
					        });
					        $list.empty().append(itemsHtml);
				        };
					    if(field.list && _options.lists[field.list] && _options.lists[field.list].list) {
					        ml_listLoad();
					    } else if(field.list) {
					        _lazyLoadList[field.list] = ml_listLoad;
					    }
					    break;
				    case 'password':
				        $li.addClass('ua-form-password');
				        
			            var pwOpts = { 
			                onchange: function() {
			                    _showMessage('New password has been set.', 2500);
			                }
			            };
			            if(_options.passwordUrl) { pwOpts.passwordUrl = _options.passwordUrl; }
			            _passwordForm = UA.User.Password(pwOpts);
			            _passwordForm.init(_manager);
			            $('<a title="Set New Password" href="javascript:void(0)" class="ua-password-change">Set Password</a>')
			                .appendTo($('.ua-form-ctrl', $li))
			                .click(function() {
			                    _passwordForm.show(_dataObj);
			                    //$(_manager).trigger('ua-manager-passwordopen', _dataObj);
			                }).hide();
			            
				        $(['<ul class="ui-state-default ua-password-new">',
		                        '<li><input type="password" id="',id,'" class="ui-state-default"' + required + ' /></li>', 
			                    '<li><input type="password" id="',id,'-2" class="ui-state-default" /></li>',
                            '</ul>'].join('')).css(css).appendTo($('.ua-form-ctrl', $li));
					    break;
					case 'yesno':
					    $li.addClass('ua-form-yesno');
					    $('<input type="checkbox" id="' + id + '" class="ui-state-default" />').css(css).prependTo($li);
					    break;
				    default:
					    required = field.required ? ' rel="required"' : '';
					    $('<input type="text" id="' + id + '" class="ui-state-default"' + required + ' />').css(css).appendTo($('.ua-form-ctrl', $li));
					    break;
			    }
			}
		}
		
		function _buildForm() {
			var $orphanList = $('<ul class="ua-form-ctrllist"></ul>').appendTo($container);
			
			$.each(_options.groups, function(key, name) {
				$fieldsets[key] = $(['<fieldset id="',_options.id,'-fs-',key,'" class="ui-state-hover">',
						'<legend>',name,'</legend>',
						'<ul class="ua-form-ctrllist"></ul>',
					'</fieldset>'].join('')).appendTo($container);
			});
			
			$.each(_options.fields, function(i, field) {
				var $list;
				if(field.group) {
					var $fs = $fieldsets[field.group];
					if($fs) {
						$list = $('ul:first', $fs);
					}
				}
				if(!$list) {
					$list = $orphanList;
				}
				
				var id = 'ua-form-field-' + (field.id || field.property);
				if(!field.property) {
				    $('<li class="ua-form-label">' + field.label + '</li>').appendTo($list);
				} else if(!field.hidden) {
				    var $li = $(['<li>',
				            '<label for="',id,'">',
				                '<strong>',field.label,'</strong>',
				            '</label>',
				            '<div class="ua-form-ctrl"></div>',
				        '</li>'].join('')).appendTo($list);
				    if(field.required) {
				        $li.addClass('ua-form-required');
				    }
				    _buildControl($li, field, id);
				}
			});
			
			$.each($fieldsets, function(key, $fs) {
			    if($('li', $fs).length === 0) {
			        $fs.hide();
			    }
			});
			
			$container.simpleValidator({
				validators: [{
					selector: '.ua-form-list-required',
					validate: function(val) {
						return $('input:checked', $(this)).length > 0;
					}
			    },{
			        selector: '.ua-form-password ul',
			        validate: function(val) {
			            var $el = $(this);
			            if($el.is(':hidden')) {
			                return true;
			            } else {
			                var pwd1 = $('input:first', $el).val(),
			                    pwd2 = $('input:last', $el).val();
			                return pwd1 === pwd2;
			            }
			        }
			    }]
			});
			
			$('.ua-form-ctrl .ui-state-default', $container).focus(function() {
				$(this).addClass('ui-state-active');
			}).blur(function() {
				$(this).removeClass('ui-state-active');
			});
			
			$(_manager).trigger('ua-form-built');
		}
		
		function _loadForm() {
		    var pkVal = _getPKValue();
			$.each(_options.fields, function(i, field) {
				var id = 'ua-form-field-' + (field.id || field.property);
				var val = _dataObj[field.property];
				if(val === undefined && field.defaultVal) {
				    val = field.defaultVal;
				}
				switch(field.type) {
					case 'date':
					    val = UA.Common.format.date(val);
						break;
					case 'singlelist':
					    if(val === undefined && field.list && _options.lists[field.list] && _options.lists[field.list].defaultVal) {
					        val = _options.lists[field.list].defaultVal;
					    }
					    break;
					case 'multilist':
						// clear any previous selections
						$('input:check', '#' + id).removeAttr('checked');
						
						var vals = [];
						if(val === undefined && field.list && _options.lists[field.list] && _options.lists[field.list].defaultVal) {
						    val = _options.lists[field.list].defaultVal;
						}
						if(typeof val === 'string') {
							vals = val.split(',');
						} else if($.isArray(val)) {
							vals = val;
						}
						
						$.each(vals, function(i, item) {
						    var itemVal = field.idfield ? item[field.idfield] : item;
						    if(typeof itemVal === 'string') {
							    itemVal = $.trim(itemVal);
							}
							var itemid = id + '-' + itemVal;
							$('#' + itemid).attr('checked', 'checked');
						});
						break;
					case 'password':
					    if(!pkVal) {
					        $('.ua-form-password .ua-password-new').show();
					        $('.ua-form-password .ua-password-change').hide();
						    $('#' + id + ', #' + id + '-2').val('');
						    if(field.required) {
				                $('li.ua-form-password').addClass('ua-form-required');
						    }
					    } else {
					        $('.ua-form-password .ua-password-new').hide();
					        $('.ua-form-password .ua-password-change').show();
				            $('li.ua-form-password').removeClass('ua-form-required');
					    }
						break;
					case 'yesno':
					    if(val) {
						    $('#' + id).attr('checked', 'checked');
						}
					    break;
					default:
						//$('#' + id).val(val || '');
						break;
				}
				
			    if(field.disabled) {
					$('#' + id).html(val);
			    } else {
					$('#' + id).val(val || '');
			    }
			});
		}
		
		function _makeObjectFromForm() {
		    var pkVal = _getPKValue();
		    var obj = {};
		    $.each(_options.fields, function(i, field) {
				var id = 'ua-form-field-' + (field.id || field.property);
				var val;
		        if(field.hidden || field.disabled) {
		            obj[field.property] = _dataObj[field.property] || field.defaultVal || '';
		            
		            if(obj[field.property] && obj[field.property].getDate) {
		                val = UA.Common.format.datetime(_dataObj[field.property]);
		            }
		        } else {
		            switch(field.type) {
		                case 'multilist':
		                    val = '';
		                    $('#' + id + ' input:checked').each(function() {
		                        if(val) { val += ','; }
		                        val += $(this).attr('rel');
		                    });
		                    break;
		                case 'password':
		                    if(!pkVal) {
		                        val = $('#' + id).val();
		                    } else {
		                        return true;
		                    }
		                    break;
		                case 'yesno':
		                    val = $('#' + id).is(':checked');
		                    break;
		                default:
		                    val = $('#' + id).val();
		                    break;
		            }
		            obj[field.property] = val;
		        }
		    });
		    
		    return obj;
		}
		
		function _showMessage(message, duration, isError) {
		    if(isError) {
		        $messages.addClass('ui-state-error');
		    } else if($messages.hasClass('ui-state-error')) {
		        $messages.removeClass('ui-state-error');
		    }
		    $messages.html(message).slideDown();
		    if(duration) {
		        setTimeout(function() { 
		            $messages.slideUp();
		        }, duration);
		    }
		}
		
		function _showValidationMessage() {
		    var count = 0, duration = 3000, message = '<h2>Form is not valid.</h2><ul>';
		    $('[rel=required], .ua-form-list-required', $container).each(function() {
		        if($(this).hasClass('ui-state-error')) {
		            count++;
		            var id = $(this).attr('id');
		            var label = $('[for=' + id + '] strong').text();
		            message += '<li><strong>' + label + '</strong> is required.</li>';
		        }
		    });
		    $('.ua-form-password ul').each(function() {
		        if($(this).hasClass('ui-state-error')) {
		            count++;
		            var id = $(this).attr('id');
		            var label = $('[for=' + id + '] strong').text();
		            message += '<li><strong>Passwords</strong> must match.</li>';
		        }
		    });
		    message += '</ul>';
		    if(count > 3) { // add .5 second for each 3 items
		        duration += (count / 3) * 500;
		    }

		    _showMessage(message, duration, true);
		}
		
		function _loadFields(complete) {
			if(_options.fieldsUrl) {
		        var params = { name:_options.formType };
		        if(_options.context) {
		            params.context = _options.context;
		        }
		        $.ajax({
		            url: _options.fieldsUrl,
		            type: 'GET',
		            data: params,
		            dataType: 'json',
		            success: function(data) {
		                _options.fields = data;
		                if(complete) {
		                    complete();
		                }
		            },
		            error: function() {
		                alert('Error getting fields');
		            }
		        });
		    } else if (complete) {
		        complete();
		    }
		    _fieldsLoaded = true;
		}
		
		function _saveClickHandler(success) {
            $messages.removeClass('ui-state-error');
			if($container.simpleValidator('valid')) {
                var pkVal = _getPKValue();
			    var obj = _makeObjectFromForm();
			    
			    obj._method = pkVal ? 'POST' : 'PUT';
			    $.ajax({
			        url: _options.url,
			        type: 'POST',
			        data: obj,
			        dataType: 'text',
			        success: function() {
                        delete obj._method;
			            if(_options.saved) {
			                _options.saved(obj);
			            }
			            if(success) {
			                success();
			            }
			        },
			        error: function(resp) {
			            _showMessage(resp.responseText, 2000, true);
			        }
			    });
			} else {
			    _showValidationMessage();
			}
		}
		
		function _setupDialog() {
			$container.addClass('ua-form-dialog').dialog({
				autoOpen: false,
				title: _options.title,
				modal: true,
				width: '500px',
				buttons: {
					'Ok': function() {
					    _saveClickHandler(function() {
				            $container.dialog('close');
					    });
					},
					'Cancel': function() {
						$(this).dialog('close');
					}
				}
			});
		}
		
		function _ensureFields(callback) {
		    if(_fieldsLoaded) {
		        callback();
		    } else {
		        _onFieldsLoaded = callback;
		    }
		}
        
        _self.init = function(manager, dataObj) {
            _manager = manager;
            
            if(dataObj) {
                _dataObj = dataObj;
            }
            
            if(_options.openOn) {
                $(_manager).bind(_options.openOn, function(evt, data) {
                    _ensureFields(function() {
                        if(data) {
                            _dataObj = data;
                        } else {
                            _dataObj = {};
                        }
				        $container.simpleValidator('reset');
				        _loadForm();
				        if(_options.dialog) {
				            $container.dialog('open');
				        }
				    });
                });
            }
            $.each(_options.lazyLoaders, function(key, loader) {
                $(_manager).bind(loader.typeName, function(evt, data) {
                    try {
			            if(_lazyLoadList[key]) {
			                if(loader.processor) {
			                    data = loader.processor(data);
			                }
			                if (!_options.lists[key]) {
			                    _options.lists[key] = {};
			                }
			                _options.lists[key].list = data;
			                _lazyLoadList[key]();
			            }
			        } catch (e) {
			            throw new Error("Unable to load data for " + key + ": " + e);
			        }
			    });
            });
            
			$container = $('<div id="'+_options.id+'" class="ui-state-default ua-form-container"></div>').appendTo(_options.target);
			$messages = $('<div class="ui-state-default ua-form-messages"></div>').appendTo($container);
			
	        _loadFields(function() {
	            _buildForm();
	            
	            if(!_dataObj) {
	                _dataObj = {};
	            }
	            if(!_options.openOn) {
	                _loadForm();
	            }

                if(_options.dialog) {
                    _setupDialog();
                } else {
                    $.each(_options.buttons, function(name, action) {
			            $('<button class="ui-state-default ua-form-actionbutton">' + name + '</button>')
			                .appendTo($container)
			                .hover(function() {
			                    $(this).addClass('ui-state-hover');
			                }, function() {
			                    $(this).removeClass('ui-state-hover');
			                })
			                .click(function() {
                                if(name === _options.saveButton) {
			                        _saveClickHandler(action);
                                } else if(name === _options.clearButton) {
                                    _loadForm();
                                    action();
                                } else {
                                    action();
                                }
			                });
			                
                    });
                }
                
                if(_onFieldsLoaded) {
                    _onFieldsLoaded();
                }
	        });
			
			$.each(_options.simpleForms, function(key, form) {
			    form.init(_manager, _self);
			});
        };
        
        _self.load = function(dataObj) {
            _dataObj = dataObj;
            _loadForm();
        };
		
		_self.setDefaultListVal = function(listKey, val) {
		    if(_options.lists[listKey]) {
		        _options.lists[listKey].defaultVal = val;
		    }
		};
        
        return _self;
    };
})(UserAdmin);