/**
 * Levels class for selecting multiple items such as categories using AJAX technology.
 * This package requires jQuery >= 1.4, ValidForm Builder HTML structures and Tools.js.
 *
 * @package FWO_Levels
 * @author  Robin van Baalen
 * @link    http://forwebonly.com
 * @version 0.2.4
 *
 * CHANGELOG
 *	0.1		First version
 *	0.2		Prototyped the function
 *	0.2.1	Added return false to addInput() and remove()
 *	0.2.2	Added optional file setting
 *	0.2.3	Changed ajax commands to more specific commands.
 *	0.2.4	Get data onload if a value is preset.
 */

/*
 * Levels class configuration
 */
function Levels(strName, strFile, levels){
    this.objBase        = $("select[name=" + strName + "]:first").parent();
	this.name			= strName;
	this.levels			= levels - 1 || 2;
    this.objAll         = $("select[name=" + strName + "]:lt(" + this.levels + ")");
    this.objLast        = $("select[name=" + strName + "]:visible:last");
    this.addLevel       = $("#addLevel");
    this.removeLevel    = $("#removeLevel");
    this.file           = strFile || "ajax.levels.php";
    this.msg            = {
                            saveLabel: "Opslaan",
                            newLabel: "Nieuw",
                            saved: "Item is opgeslagen",
                            removed: "Item is verwijderd.",
                            confirmDelete: "Als je een item wist, worden ook alle onderliggende items gewist. Wil je doorgaan?"
                        };

	this.load();

}

/**
 * Initiate the Levels class
 */
Levels.prototype.load = function(){
	var __this = this;

	$("select[name=" + __this.name + "]").parent().addClass("levels");

    __this.hide(__this.objBase.next(), true);
    __this.objAll
		.live("change", function(){
		   if($(this).val() !== ""){
			   __this.get($(this).parent().next());
		   }
		   else {
			   __this.hide($(this).parent().next());
		   }
		})
		.each(function(){
			// Get the data onload
			if($(this).val() !== ""){
			   __this.get($(this).parent().next());
		   }
		   else {
			   __this.hide($(this).parent().next());
		   }
		});
    __this.addLevel.live("click", function(){
		__this.addInput($(this));
		return false;
	});
    __this.removeLevel.live("click", function(){
		__this.remove($(this));
		return false;
	});

    // Identify all elements with ID's
//    __this.objBase.parent().find("div").each(function(i){
//        $(this).attr("id","lvl__" + i);
//    });

    // Make them editable if preloaded with values
    __this.objAll.each(function(){
        if($(this).val() !== ""){
            $(this).parent().show();
        }
    })
}

/**
 * Erase all values but keep the DOM object
 * @param $objAffected  Object to refresh
 */
Levels.prototype.flush = function($objAffected){
	var __this = this;

    if($objAffected.find("select").length > 0){
        $objAffected.find("option").remove();
        __this.hide($objAffected.next());
    }
}

/**
 * Hide levels
 * @param $objAffected   Current, changed, object. Next object will be hidden.
 * @param blnLoad        If Levels.hide is called onload, do hide() instead of fadeOut();
 */
Levels.prototype.hide = function($objAffected, blnLoad){
	var __this		= this,
		$objNext    = $objAffected.next().find("select[name=" + __this.name + "]"),
        blnLoad     = blnLoad || false;

    (blnLoad) ? $objAffected.hide() : $objAffected.fadeOut();
    ($objNext.length > 0 && blnLoad) ? __this.hide($objNext.parent(), blnLoad) : $objNext.parent().fadeOut();

}

/**
 * Get the levels using an ajax call
 * @param $objAffected The affected jQuery object to apply the results to (the parent DIV)
 */
Levels.prototype.get = function($objAffected){
	var __this		= this,
		intParent	= __this.getParent($objAffected);
    
    $.post(__this.file, {action: "Levels__get", intLevel: intParent, noCache: Math.floor(Math.random()*9999)}, function(data){

        __this.flush($objAffected); // Clear the next select list before adding new data

        if(data.length > 0){
            $objAffected.find("select").append(data);
            __this.show($objAffected);
        }
        
    }, "html");
}

/**
 * Save a new domain
 * @param intParent The parent ID
 * @param strLevel  The name of the new level
 */
Levels.prototype.set = function(intParent, strLevel){
	var __this		= this;

    $.post(__this.file, {action: "Levels__set", strLevel: strLevel, intLevel: intParent, noCache: Math.floor(Math.random()*9999)}, function(data){
        if(data === "saved"){
            __this.removeInput();
            __this.success(__this.msg.saved);
        }
    }, "html");
}

/**
 * Remove a selected level
 */
Levels.prototype.remove = function($objRemove){
	var __this			= this,
		$objAffected    = $objRemove.parent().parent(),
        intLevel        = $objAffected.find("select").val();

    if(confirm(__this.msg.confirmDelete)){
        $.post(__this.file, {action: "Levels__del", intLevel: intLevel, noCache: Math.floor(Math.random()*9999)}, function(data){
            if(data === "removed"){
                __this.get($objAffected);
                __this.success(__this.msg.removed);
            }
        });
    }
}

/**
 * User feedback message
 */
Levels.prototype.success = function(strMsg){
	var __this		= this;

    __this.objBase.parent().append(Forms.success(strMsg));
    setTimeout(function(){
        __this.objBase.parent().find(".success").fadeOut();
    }, 1500);
}

/**
 * Remove the input field for a new Level
 */
Levels.prototype.removeInput = function(){
	var __this		= this,
		$objNext	= $("#newLevel").parent().next();

    $("#newLevel").parent().next().find("select option:first").attr("selected","selected"); // Select the newly created level
    $("#newLevel").parent().remove(); // Remove the insert item.

    __this.get($objNext); // Get all sublevels, refresh the selectlist content.
}

/**
 * Add input field to the dom
 * @param strLocation "before" to insert the input field before the current element. "after" to insert it after the current element in the DOM.
 */
Levels.prototype.addInput = function($objAdd){
	var __this		= this,
		$objSelect  = $objAdd.parent().parent(),
        strLocation = strLocation || "before",
        $objInput   = $("<div class='vf__required newItem' id='addNew'><label for='newLevel'></label><input class='vf__text' type='text' name='newLevel' id='newLevel' /><button class='vf__button' name='saveLevel' id='saveLevel'></button></div>");

    // Hide next elements
    __this.hide($objAdd.parent());

    // Add labels
    $objInput.find("button").text(__this.msg.saveLabel);
    $objInput.find("label").text(__this.msg.newLabel);
    
    // Work some magic
    switch(strLocation){
        default:
            $objSelect.before($objInput);
            $objSelect.hide();
            break;
        case "after":
            $objSelect.after($objInput);
            break;
    }
    
    
    $objInput.find("input").bind("blur", function(){
        if($(this).val() == ""){
            __this.removeInput();
        }
    }).focus();
    $objInput.find("button")
        .unbind("click") // Clear previous bindings
        .bind("click", function(){
            var strNewLevel = $(this).prev().val().capitalize(), // Uses the Tools.js library
                intParent   = __this.getParent($(this).parent()); // Get the previous item. Current item is input div.

            if(strNewLevel.length > 0){
                $(this).prev().val(strNewLevel); // Set the new capitalized value.
                __this.set(intParent, strNewLevel, $objSelect);
            }
            
            return false;
        });
}

/**
 * Show the affected level selectors
 */
Levels.prototype.show = function($objElement){
    $objElement.fadeIn();
    $objElement.find("small").show(); // @todo This is a nasty hack
}

/**
 * Get the ID of the parent element
 * @param $objCurrent   jQuery object of the current element
 */
Levels.prototype.getParent = function($objCurrent){
	var __this			= this,
		$objCurrent     = $objCurrent || __this.objBase,
        $objPrevSelect  = $objCurrent.prev().find("select");

    if($objPrevSelect.length > 0){
        // There is a parent
        return $objPrevSelect.val();
    }
    else {
        return 0; // The parent element is reached.
    }
}
