// JavaScript application for LetterSetter
// 
//	

var imagerRootURL = "http://lettersetter.net/cgi-bin/ls?";
var dataRootURL = "ls/layouts.json";



//<table class="controlpanel">
//	<tr>
//		<td class="controlpanelsection">
//			1
//			</td>
//		<td class="controlpanelsection">
//			2
//			</td>
//		</tr>
// 	</table>

Controller = function(foundryName, layoutName, showLayoutMenu){
    // app for lettersetter application
    bindMethods(this);
    log("Hello, this is the controller.");
    log("Version 0.5");
    this.layoutSelection = null;
	this.foundryName = foundryName;
    this.layoutName = layoutName;
	this.showLayoutMenu = showLayoutMenu;
	this.layoutHeight = null;
	this.layoutWidth = null;
    //this.selectedFontIndex = 1;
	log("attempt to start with", layoutName);
    this.text = "Welcome";
    this.allText = new Array;
    this.textBoxes = null;
    this.selectedFontIndex = null;
    this.updatePollTime = .5
    /* flag set to true if the user has typed something - respect the content from then on*/
    this.userSetText = false;
    // get started	
    this.loadLayoutSelection(dataRootURL);
}

Controller.prototype.errorLoadLayoutSelection = function(results){
    // callback when the loading has failed
    log("can't load the Layout selection", results);
}

Controller.prototype.doneLoadLayoutSelection = function(results){
    // callback when the loading has succeeded
    //log("Layout selection loaded!", results);
    this.layoutSelection = results;
    //log('results', results);
    //log('layouts', results.layouts);
    //log('items in layouts', results.layouts.length);
	if(this.showLayoutMenu==true){
	    this.buildAllLayoutMenus();
	}
	this.findLayoutByName();
}

Controller.prototype.loadLayoutSelection = function(LayoutDataURL){
	// try to load the layout data from the json url.
    //log("loadLayoutSelection attempt on", LayoutDataURL);
    var d  = loadJSONDoc(LayoutDataURL);
    d.addCallback(this.doneLoadLayoutSelection);
    d.addErrback(this.errorLoadLayoutSelection);
    //log("loadLayoutSelection", d);
}

Controller.prototype.buildAllLayoutMenus = function(){
	// Build a form menu with the nice layout names
    //log("buildAllLayoutMenus");
    // build the layout menu
    menuItems = new Array;
    for (i=0; i<this.layoutSelection.layouts.length; i++){
        menuItems.push(this.layoutSelection.layouts[i]);
    }
    //log("buildAllLayoutMenus menuItems", menuItems);
    formList = FORM( {'onsubmit':'app.callbackTextBoxChange(); return false;', 'name':'layoutmenu'},
        INPUT({'type':'hidden', 'name':'layout', 'value':this.layoutName}),
        SELECT({'name':'fontNames', 'onchange':"app.callbackFontMenuChange(this.form, 'fontNames')"}, 		map(this.wrapFontPopupListItem, menuItems)));
    element = getElement('layoutmenulocation');
    //log("buildAllLayoutMenus element", element);
    swapDOM(element, SPAN({'id':'layoutmenulocation'}, P({"class": "lettersetterfeaturebox"},formList)));
    //log("buildAllLayoutMenus done");
}

Controller.prototype.wrapFontPopupListItem = function (fontItem) {
	// Wrap a single item for the layout menu
    if(fontItem.menuname==this.layoutName){
        return OPTION({'value': fontItem.layoutname, "selected":1}, fontItem.menuname);
    }
    else{
        return OPTION({'value': fontItem.layoutname}, fontItem.menuname);
    }
}

Controller.prototype.findLayoutByName = function () {
	// Find the index for a given layout name
    log("findLayoutByName:", this.layoutName);
	var foundIt = false;
    for (i=0; i<this.layoutSelection.layouts.length; i++){
		if(this.layoutSelection.layouts[i].layoutname == this.layoutName){
			this.selectedFontIndex = i;
		    this.setFontAndText(this.selectedFontIndex);
		    this.makeInputBoxes(this.selectedFontIndex);
			log("findLayoutByName >>", this.layoutSelection.layouts[i].layoutname)
		    //this.update();
			foundIt = true;
		}
    }
	if(foundIt == true){
	    log("findLayoutByName found!", this.selectedFontIndex, this.layoutName);
	}
	else{
	    log("findLayoutByName not found!", this.selectedFontIndex);
	    this.selectedFontIndex = selectedIndex = 0;
	    this.setFontAndText(this.selectedFontIndex);
	    this.makeInputBoxes(this.selectedFontIndex);
		log("findLayoutByName finding alternative", this.layoutSelection.layouts[i].layoutname)
	    //this.update();
	}
    //log("findLayoutByName done");
}

Controller.prototype.startWithFirstFont = function () {
    //log("startWithFirstFont");
    this.selectedFontIndex = selectedIndex = 1;
	//log("this.layoutSelection", this.layoutSelection.layouts[selectedIndex].layoutname);
    this.layoutName = this.layoutSelection.layouts[selectedIndex].layoutname;
    this.setFontAndText(selectedIndex);
    this.makeInputBoxes(selectedIndex);
    //log("startWithFirstFont done");
}

Controller.prototype.callbackFontMenuChange = function (formThing, formName) {
    // the callback from the forms
    //log("callbackFontMenuChange", formThing, formName);
    this.selectedFontIndex = selectedIndex = formThing[formName].selectedIndex;
    //log("callbackFontMenuChange selectedIndex", selectedIndex);
    this.layoutName = this.layoutSelection.layouts[selectedIndex].layoutname;
    //log("callbackFontMenuChange layoutname", this.layoutName);
    // keep an array of loaded components and check if we need to get more
    // start loading the missing interface components
    this.setFontAndText(selectedIndex);
    this.makeInputBoxes(selectedIndex);
}

Controller.prototype.makeInputBoxes = function (selectedIndex){
    // make input text boxes for each text box specified in the layout
    //log("makeInputBoxes", selectedIndex);
    selectedLayoutRecord = this.layoutSelection.layouts[selectedIndex];
    this.selectedLayoutRecord = selectedLayoutRecord;
    //log("makeInputBoxes selectedLayoutRecord", selectedLayoutRecord);
    this.textBoxes = inputs = selectedLayoutRecord['textboxes'];
    features = selectedLayoutRecord['features'];
    controls = new Array;
    //log("makeInputBoxes, inputs", inputs);
    for(textBoxIndex=0; textBoxIndex<selectedLayoutRecord['textboxes'].length; textBoxIndex++){
        // see if there still is some input from a previous hit
        previousContent = this.allText[textBoxIndex];
        if(previousContent==null){
            // what if there wasn't:
            previousContent = 'Try me!';
        }
        //log("makeInputBoxes previousContent", textBoxIndex, previousContent);
        controls.push(this.mapInputBoxitem(previousContent, textBoxIndex, selectedLayoutRecord['textboxes'][textBoxIndex], selectedLayoutRecord['state'][textBoxIndex], features) );
    }
    formList = FORM( {'onsubmit':'app.callbackTextBoxChange(); return false;', 'id':'inputmenu', 'name':'inputmenu'}, controls);
    element = getElement('inputmenulocation');
    swapDOM(element, SPAN({'id':'inputmenulocation'}, formList));
}

Controller.prototype.mapInputBoxitem = function(previousContent, textBoxIndex, inputBoxitem, controlsItem, allFeatures){
    // make a box for a single textbox with input form and list of the features and their current states. Show the state of each feature.
    // Edited to make the list of available features depend on whatever is listed in the controls
    // not in the features list.
    //log("mapInputBoxitem", inputBoxitem, controlsItem, allFeatures);
    featureNameList = new Array;
    for(j=0; j<allFeatures.length; j++){
        featureName = allFeatures[j];
        //log("mapInputBoxitem featureName", featureName);
        if(controlsItem[featureName]==true){
            value = "on";
            featureState = '0';
            style = "featureControlOn";
        }
        else{
            if(controlsItem[featureName]!=null){
                value = "off";
                featureState = '1';
                style = "featureControlOff";
            }
        }
        cmd = "app.callbackFeatureStateButton("+textBoxIndex+",'"+featureName+"',"+featureState+"); return false;";
        // note: this is not the right way to install an event on an anchor.
        // but it works in safari and firefox, and might be enough for the demo.
        buttonCode = A({"class":"lettersetterFeatureStateButton", "onclick":cmd}, " "+featureName+" ");
        //log('buttonCode', buttonCode);
        featureNameList.push(SPAN({"class":style}, buttonCode));
    }
    return P({"class":"lettersetterfeaturebox"},
        INPUT({'onchange':"app.callbackTextBoxChange();", 'value':previousContent, 'name':inputBoxitem, 'maxlength':50, 'type':'text', 'size':15}), featureNameList );
}


Controller.prototype._org_mapInputBoxitem = function(previousContent, textBoxIndex, inputBoxitem, controlsItem, allFeatures){
    // make a box for a single textbox with input form and list of the features and their current states. Show the state of each feature.
    // This is the original
    //log("mapInputBoxitem", inputBoxitem, controlsItem, allFeatures);
    featureNameList = new Array;
    for(j=0; j<allFeatures.length; j++){
        featureName = allFeatures[j];
        //log("mapInputBoxitem featureName", featureName);
        if(controlsItem[featureName]==true){
            value = "on";
            featureState = '0';
            style = "featureControlOn";
        }
        else{
            value = "off";
            featureState = '1';
            style = "featureControlOff";
        }
        cmd = "app.callbackFeatureStateButton("+textBoxIndex+",'"+featureName+"',"+featureState+"); return false;";
        // note: this is not the right way to install an event on an anchor.
        // but it works in safari and firefox, and might be enough for the demo.
        buttonCode = A({"class":"lettersetterFeatureStateButton", "onclick":cmd}, " "+featureName+" ");
        //log('buttonCode', buttonCode);
        featureNameList.push(SPAN({"class":style}, buttonCode));
    }
    return P({"class":"lettersetterfeaturebox"},
        INPUT({'onchange':"app.callbackTextBoxChange();", 'value':previousContent, 'name':inputBoxitem, 'maxlength':50, 'type':'text', 'size':15}), featureNameList );
}


Controller.prototype.callbackFeatureStateButton = function(textBoxIndex, aFeatureName, theNewState){
    //log("callbackFeatureStateButton", textBoxIndex, aFeatureName, theNewState);
    if(theNewState==1){
        //log("callbackFeatureStateButton 1")
        this.layoutSelection.layouts[this.selectedFontIndex]['state'][textBoxIndex][aFeatureName] = true;
        //log("callbackFeatureStateButton 2")
    }
    else{
        //log("callbackFeatureStateButton 3")
        this.layoutSelection.layouts[this.selectedFontIndex]['state'][textBoxIndex][aFeatureName] = false;
        //log("callbackFeatureStateButton 4")
    }
    this.update();  
    //this.setFontAndText(this.selectedFontIndex);
    this.makeInputBoxes(this.selectedFontIndex);
}

Controller.prototype.makeFeatureQuery = function(selectedIndex, fKeys, fValues){
    // Make the feature part of the image query
    //log("makeFeatureQuery 1");
    //fKeys = new Array;
    //fValues = new Array;
    
    // alright, let's see if we can still find the data.
    selectedLayoutRecord = this.layoutSelection.layouts[selectedIndex];
    //log("makeFeatureQuery 2");
    allFeatures = this.layoutSelection.layouts[selectedIndex]['features'];
    //log("makeFeatureQuery 3");
    for(tb=0; tb<this.layoutSelection.layouts[selectedIndex]['textboxes'].length; tb++){
        //log("makeFeatureQuery 4", tb);
        for(tf=0; tf<this.layoutSelection.layouts[selectedIndex]['features'].length; tf++){
            //log("makeFeatureQuery 4", tf);
            featureCode = this.layoutSelection.layouts[selectedIndex]['features'][tf];
            state = this.layoutSelection.layouts[selectedIndex]['state'][tb][featureCode];
            //log("makeFeatureQuery", featureCode, state, this.layoutSelection.layouts[selectedIndex]['state'][featureCode]);
            fKeys.push("tf"+(tb+1));
            if(state==true){
                fValues.push(featureCode+".1");
            }
            else{
                fValues.push(featureCode+".0");
            }
        }
    }
    //return fKeys, fValues;
}

Controller.prototype.callbackTextBoxChange = function(){
    //log("callbackTextBoxChange this.textBoxes", this.textBoxes);
    this.allText = new Array;
    for(i=0; i<this.textBoxes.length; i++){
        //log("callbackTextBoxChange checking", this.textBoxes[i])
        aForm = getElement("inputmenu");
        //log("1", aForm);
        aBox = aForm[this.textBoxes[i]];
        //log("2", aBox);
        //log("3", aBox.value);
        this.allText.push(aBox.value);
    }
    //log("alltext", this.allText);
    this.update();  
}

Controller.prototype.setFontAndText = function(fontIndex){
    //log("setFontAndText 1");
    // switch the sample to this fontname and text
    selectedLayoutRecord = this.layoutSelection.layouts[fontIndex];
    layoutName = selectedLayoutRecord.layoutname;
    menuName = selectedLayoutRecord.menuname;
	this.layoutHeight = selectedLayoutRecord.size[1];
	this.layoutWidth = selectedLayoutRecord.size[0];

	log("--setFontAndText", this.layoutName, layoutName);
    
    //log("setFontAndText 2");
    //log("setFontAndText", fontName, text);
    this.layoutName = layoutName;
    
    //log("setFontAndText 3");
    // set the fields in the form
    element = getElement('textinput');
    //log("form input?", element)
    setNodeAttribute(element, "value", this.text);
    
    //log("setFontAndText 4");
    // set the fontname in the title
    element = getElement('layoutnametitle');
	if(element == null){
		// pass
	}
	else{
	    newElement = H1({'id':'layoutnametitle'}, "LetterSetter™ showing "+menuName);
	    //log("setFontAndText 5", element, newElement);
	    swapDOM(element, newElement);
	}
    this.update();		
}



// updating

Controller.prototype.dummyUpdate = function(){
    //log("dummy update");
}

Controller.prototype.update = function(){
    // start the image update process.
    // get the url, start downloading
    // when the image is complete, put it on screen
    //log("simple update");
    altString = 'Copyright LetterSetter and Others - All rights reserved - Demo purposes only.';
    keys = new Array();
    values = new Array();
    keys.push("foundry");
    values.push(this.foundryName);
    keys.push("layout");
    log("update: this.layoutName", this.layoutName);
    values.push(this.layoutName);
    //for(i=0; i<this.allText.length; i++){
    for(i=0; i<this.allText.length; i++){
        keys.push(this.textBoxes[i]);
        values.push(this.allText[i]);
    }
    this.makeFeatureQuery(this.selectedFontIndex, keys, values);
    query = queryString(keys, values);
    src = "http://lettersetter.net/cgi-bin/ls?" + query;
    log("query", src);
    if(this.dummyLoader==null){
        // it's loading something else already
        this.dummyLoader = new Image();
    }
    this.dummyLoader.src = src;
    this.dummyLoadCount = 0;
    callLater(this.updatePollTime, this.isUpdateReady);
}
    
Controller.prototype.deferredupdate = function(){
    if(this.deferredUpdate!=null){
        log("cancelling load");
        this.deferredUpdate.cancel();       
    }
    //log("prepping new load");
    this.deferredUpdate = callLater(this.deferUpdateTime, this.deferUpdate);        
    // show progress indicator..
    //log("isUpdateReady start");
    //swapDOM('workingindicator', SPAN({'class':'workingindicator'}, IMG({'src':'ls/rendering.gif', 'height':"7", 'width':"7"})));
}

Controller.prototype.deferUpdate = function(){
    // Foil some angry clickers, wait for a request to cool down
    log("starting new load");
    var url = imagerRootURL + this.getQueryParameters();
    log('imager url', url);
    if(this.dummyLoader==null){
        // it's loading something else already
        this.dummyLoader = new Image();
    }
    this.dummyLoader.src = url;
    this.dummyLoadCount = 0;
    callLater(this.updatePollTime, this.isUpdateReady);
    log("isUpdateReady go!");
}

Controller.prototype.isUpdateReady = function(){
    // Pollback to see if a new sample image has loaded.
    //log("isUpdateReady poll");
    if(this.dummyLoader.complete){
        // yes we are done
        log("isUpdateReady done");
        // apply the url to the sample
        altString = 'copyright PhotoLettering - all rights reserved.';
        //swapDOM('mainsample', IMG({'class':'mainsample', 
        //    'id':'mainsample', 'src':src, 'alt':altString, 'width':510, 'height':300}));
        swapDOM('mainsample', IMG({'class':'mainsample', 
            'id':'mainsample', 'src':this.dummyLoader.src, 'alt':altString}));
        this.dummyLoadCount = 0;
        this.dummyLoader = null;
        this.deferredUpdate = null;
        //swapDOM('workingindicator', SPAN({'class':'workingindicator'}) );
    }
    else{
        // no it's not done
        log("isUpdateReady not done, tries", this.dummyLoadCount);
        this.dummyLoadCount += 1;
        if (this.dummyLoadCount > this.maxLoadTries){
            // we're running out of patience
            // remove indicator
	        //swapDOM('workingindicator', SPAN({'class':'workingindicator'}) );
            altString = "Sorry, we've got some sort of problem..";
            swapDOM('mainsample', IMG({'class':'mainsample', 
                'id':'mainsample', 'src':errorImageURL, 'alt':altString,
				'height': this.layoutHeight, 'width': this.layoutWidth}));
            log("xxx uh oh", this.dummyLoadCount);
        }
        else{
            // alright, let's wait some more
            callLater(this.updatePollTime, this.isUpdateReady);
        }
    }
}




