﻿/**
*   Madlib generator
*   Aaron Lile 2008
*   aaron.lile@gmail.com
*
*   makes use of the utility.js "library" functions ( $(), dw(), trace(), enTag() )
*/

// component IDs
var topDiv; // the main wrapper div id
var headerDiv = "header"; // instruction / initial data entry
var optionsDiv = "options"; // holds the list of word option groups
var sentenceDiv = "sentence"; // the return div for the "Mad Libs"
var optionsForm = 'optionsForm'; // the form that holds all the test select groups et al
// instruction message
var instructions = '';
// data entry (one item...)
var textInput = 'textInput';
// count of items
var count = 0;
// parts of grammar array
var grammar = ['noun', 'adjective', 'verb', 'adverb'];
// word collector and phrase/sentence holder arrays
var nouns = [];
var adjectives = [];
var verbs = [];
var adverbs = [];
var nounPhrases = [];
var verbPhrases = [];
var sentences = [];

/**
*   Starts the whole thing off
*   @ param id - string id of the wrapper div (can't just have a bare <body>
*/
function init(id)
{
    topDiv = id;
    
    if(topDiv)
    {
        // set up the page structure
        buildDiv(headerDiv);
        buildDiv(optionsDiv);
        buildDiv(sentenceDiv);
        
        // set the header
        setHeader();
    }
}


/**
*   Builds the header content, also makes sure that the other divs are not seen
*/

function setHeader()
{
    hide(sentenceDiv);
    hide(optionsDiv);
    show(headerDiv);
    // welcome message
    instructions = 'Welcome to the MAD JS_LIBS generator.  Enter a number below to get started.';
    setInstructions(headerDiv);
    // data collection elements
    var input = enTag('input', null, {id:textInput});
    var button = enTag('button', 'Go!', {type:'button', onclick:'setOptions()'});
    var holder = enTag('form', input + button);
    $(headerDiv).innerHTML += holder;
}

/**
*   sets out a count of option elements equal to the value submitted
*/
function setOptions()
{
    count = parseInt($(textInput).value);
    // base validation of the input - if is a number, continue
    if(isNaN(count) || count <= 0)
    {
        setHeader();
        alert('Please enter a number that is greater than zero');
    }
    else
    {
        // a bit redundant, but not sure of a good solution off-hand
        hide(sentenceDiv);
        hide(headerDiv);
        show(optionsDiv);
        // set instructions
        instructions = 'For each word, select the part of speech you want and then enter the value in';
        instructions += '<br/>the box.  Please note that you will get better results if you use';
        instructions += '<br/>present-tense verbs and singular nouns.  You are of course free to';
        instructions += '<br/>put in any sort of text you want.';
        setInstructions(optionsDiv);
        // create the reset button
        setReset(optionsDiv);
        // make some boxes!
        var options = '';
        for(var i = 0; i < count; i++)
        {
            var select = setSelectBox(grammar, {id:'select' + i});
            var text = enTag('input', null, {type:'text', size:30, id:'text' + i});
            var lineBreak = '<br/>';
            options += select + text + lineBreak;
        }
        var button = enTag('button', 'Submit');
        var optionForm = enTag('form', options + button, {id:optionsForm, onsubmit:"return setSentences(this)"});
        
        $(optionsDiv).innerHTML += optionForm;
    }
}

function setSentences(form)
{
    hide(optionsDiv);
    hide(headerDiv);
    show(sentenceDiv);
   
    for(var i = 0; i < count; i++)
    {
        var sel = 'select' + i;
        var txt = 'text' + i;
        var val = form[sel].value;
        var word = form[txt].value;

        // parse responses into arrays
        switch(val)
        {
            case 'noun':
                nouns.push(word);
                break;
            case 'verb':
                verbs.push(word);
                break;
            case 'adverb':
                adverbs.push(word);
                break;
            case 'adjective':
                adjectives.push(word);
                break;
            default:
                break;
                
        }
    }
    // associate nouns/adjectives and verbs/adverbs into nounPhrases and verbPhrases,
    //  also getting the article (a/the) in front of the NP, and a VP linkage as well
    if(nouns.length > 0)
    {
        setNounPhrases();
        if(verbs.length > 0) setVerbPhrases();
        // put em together!
        buildPhrases();
    }
    
}

/**
*   Compares the count of nouns[] and adjectives[] and assigns them randomly
*       Determines whether will be IO(a/an) or DO(the)
*       Then pushes each into nounPhrases[]
*/
function setNounPhrases()
{
    var nounCount = nouns.length;
   
    for(var i = 0; i < nounCount; i++)
    {
        var n = '';
        var adj = '';
        var article = (Math.random < .5) ? 'IO' : 'DO';
        // pull a random noun out of the array, then shorten it
        var nIndex = Math.floor(Math.random() * nouns.length);
        n =  nouns.splice(nIndex, 1).toString(); 
        var diff = nouns.length - adjectives.length;
        
        // determine number of adjectives the NP will have
        if(adjectives.length == 0) // then we have nothing to do with the adjs
        {
            // do nothing .... 
        }
        else if(diff == 0) // then have a 1:1 between noun and adjective
        {
            var adjIndex = Math.floor(Math.random() * adjectives.length);
            adj =  adjectives.splice(adjIndex, 1).toString();
        }
        else if(diff < 0 && nouns.length >= 1) // then we have more adj than nouns, and more than one noun remaining
        {
            var count = Math.ceil(Math.random() * adjectives.length);
            for(var j = 0; j < count; j++)
            {
                var adjIndex = Math.floor(Math.random() * adjectives.length);
                adj +=  adjectives.splice(adjIndex, 1).toString() + " "; 
            }
        }
        else if(diff < 0 && nouns.length == 0) // more adj, but only one noun, so it gets em all!
        {
            for(var j = 0; j <= adjectives.length; j++)
            {
                var adjIndex = Math.floor(Math.random() * adjectives.length);
                adj +=  adjectives.splice(adjIndex, 1).toString() + " "; 
            }
        }
        else // fewer adjectives than nouns
        {
            // randomly assign the adjective
            if(Math.random > .5)
            {
                var adjIndex = Math.floor(Math.random() * adjectives.length);
                adj =  adjectives.splice(adjIndex, 1).toString();
            }
        }
        // set the IO / DO
        if(article == 'DO')
        {
            var art = 'The';
        }
        else
        {
            switch(adj[0].toLowerCase())
            {
                case 'a':
                case 'e':
                case 'i':
                case 'o':
                case 'u':
                    art = 'An';
                    break;
                default:
                    art = 'A';
            }
        }
        
        nounPhrases.push(art +" " + adj + " " + n);
    }
}

/**
*   Basically the same as setNounPhrases, but there is more complexity in determining the linkage and modifying the verb
*       accordingly.
*/
function setVerbPhrases()
{
 var verbCount = verbs.length;
   
    for(var i = 0; i < verbCount; i++)
    {
        var v = '';
        var adv = '';
        var linkage = 'gerund'//(Math.random < .5) ? 'normal' : 'gerund';
        // pull a random noun out of the array, then shorten it
        var vIndex = Math.floor(Math.random() * verbs.length);
        v =  verbs.splice(vIndex, 1).toString(); 
        var diff = verbs.length - adverbs.length;
        
        
        if(adverbs.length == 0) 
        {
            
        }
        else if(diff == 0)
        {
            var advIndex = Math.floor(Math.random() * adverbs.length);
            adv =  adverbs.splice(advIndex, 1).toString();
        }
        else if(diff < 0 && verbs.length >= 1)
        {
            var count = Math.ceil(Math.random() * adverbs.length);
            for(var j = 0; j < count; j++)
            {
                var advIndex = Math.floor(Math.random() * adverbs.length);
                adv +=  adverbs.splice(advIndex, 1).toString() + " "; 
            }
        }
        else if(diff < 0 && verbs.length == 0)
        {
            for(var j = 0; j <= adverbs.length; j++)
            {
               var advIndex = Math.floor(Math.random() * adverbs.length);
                adv +=  adverbs.splice(advIndex, 1).toString() + " "; 
            }
        }
        else
        {
            
            if(Math.random > .5)
            {
                var advIndex = Math.floor(Math.random() * adverbs.length);
                adv =  adverbs.splice(advIndex, 1).toString();
            }
        }
        // set the verb form and the linkage
        if(linkage == 'normal')
        {
            var link = ' ';
            var ending = 's';
        }
        else
        {
            var link = 'is';
            // modify the verb based on its last letter - not perfect, but functions
            switch(v[v.length - 1].toLowerCase())
            {
                // remove the last letter
                case 'a':
                case 'e':
                case 'i':
                case 'o':
                case 'u':
                    v = v.substr(0, v.length - 1);
                    break;
                // double the last letter
                case 'g':
                case 'm':
                case 'n':
                case 'p':
                case 'r':
                case 't':
                    v += v[v.length - 1];
                    break;
                // do nothing
                default:
                    break;
            }
            var ending = 'ing';
        }
        
        verbPhrases.push(" " + link + " " + adv + " " + v + ending);
    }
}

/**
*   Basically the same as setNounPhrases() and setVerbPhrases(), which means i should refactor
*      the functionality.  mebbe next time.  Combines the NPs and the VPs, and 'prints' the phrases.
*/
function buildPhrases()
{
    var npCount = nounPhrases.length;
   
    for(var i = 0; i < npCount; i++)
    {
        var np = '';
        var vp = '';
       
        // pull a random np out of the array, then shorten it
        var npIndex = Math.floor(Math.random() * nounPhrases.length);
        np =  nounPhrases.splice(npIndex, 1).toString(); 
        var diff = nounPhrases.length - verbPhrases.length;
        
        
        if(verbPhrases.length == 0) 
        {
            
        }
        else if(diff == 0)
        {
            var vpIndex = Math.floor(Math.random() * adverbs.length);
            vp = verbPhrases.splice(vpIndex, 1).toString();
        }
        else if(diff < 0 && verbPhrases.length >= 1)
        {
            var count = Math.ceil(Math.random() * verbPhrases.length);
            for(var j = 0; j < count; j++)
            {
                var vpIndex = Math.floor(Math.random() * verbPhrases.length);
                vp +=  verbPhrases.splice(vpIndex, 1).toString() + " "; 
            }
        }
        else if(diff < 0 && verbPhrases.length == 0)
        {
            for(var j = 0; j <= verbPhrases.length; j++)
            {
               var vpIndex = Math.floor(Math.random() * verbPhrases.length);
                vp +=  verbPhrases.splice(vpIndex, 1).toString() + " "; 
            }
        }
        else
        {
            if(Math.random > .5)
            {
                var vpIndex = Math.floor(Math.random() * adverbs.length);
                vp = verbPhrases.splice(vpIndex, 1).toString();
            }
        }
        
        sentences.push(np + vp);
    }
    
    for(var n = 0; n < sentences.length; n++)
    {
        var text = enTag('p', sentences[n] + ".");
        $(sentenceDiv).innerHTML += text;
    }
    setReset(sentenceDiv);
}
/**
*   Sets the reset button up at the top of element:id
*/
function setReset(id)
{
    var button = enTag('button', 'Reset Mad JS_libs', {onclick:'setHeader()', style:'margin-bottom:15px;'});
    var holder = enTag('form', button);
    $(id).innerHTML += holder;
}
// internal utility functions - maybe want to add some to utility.js?

/**
*   Very simple - applies the value of instructions to the element.id
*/
function setInstructions(id)
{
    $(id).innerHTML = enTag('p',instructions);
}

/**
*   Turns the visible property of the element.ID off
*/
function hide(id)
{
    $(id).style.visibility = "hidden";
    $(id).innerHTML = '';
}

/**
*   Turns the visible property of the element.ID on
*/
function show(id)
{
    $(id).style.visibility = "visible";
    $(id).style.top = 0;
}

/**
*   Puts a new div inside of div#topDiv
*   @ param id - string id for the new div
*/
function buildDiv(id)
{
    if(!$(id) && $(topDiv))
    {
        $(topDiv).innerHTML += enTag('div', null, {id:id, style:'position:absolute'});
    }
}

/**
*   Builds a select box 
*   @ param values - array containing the values to be in the options
*   @ param htmlOptions - object with name/value pairs to pass to entag
*   @ return selectBox - a string with the HTML elements
*/

function setSelectBox(values, htmlOptions)
{
    var options = '';
    
    for(var i = 0 ; i < values.length; i++)
    {
        options += enTag('option', values[i], {value:values[i]});
    }
    
    var selectBox = enTag('select', options, htmlOptions);
    return selectBox;
}