/***

netProtozo.com
Grid Construction Kit (beta)

// 
// This software is published under BSD licence.
//##############################################################################
//* Copyright (c) 2009, Karl Llewellyn [kllewellyn|at|gmail|dot|com]
//* All rights reserved.
//* Redistribution and use in source and binary forms, with or without
//* modification, are permitted provided that the following conditions are met:
//*
//*     * Redistributions of source code must retain the above copyright
//*       notice, this list of conditions and the following disclaimer.
//*     * Redistributions in binary form must reproduce the above copyright
//*       notice, this list of conditions and the following disclaimer in the
//*       documentation and/or other materials provided with the distribution.
//*     * Neither the name of netProtozo.com nor the names of its contributors may 
//*       be used to endorse or promote products derived from this software
//*       without specific prior written permission.
//*
//* THIS SOFTWARE IS PROVIDED BY COPYRIGHT HOLDERS ``AS IS'' AND ANY
//* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
//* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
//* DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
//* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
//* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
//* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
//* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
//* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
//* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//* 
//##############################################################################

***/
window.np = {};

/***

np.Grid

***/
np.Grid = {

    unit : 10, 
    
    gutter : { 
        units: 1,
        size: function() { 
            return (np.Grid.unit * this.units);
        }
    },
    
    margin : { 
        top: { 
            units: 2,
            size: function() { 
                return (np.Grid.unit * this.units)||0;
            }
        },
        left: { 
            units: 2,
            size: function() { 
                return (np.Grid.unit * this.units)||0;
            }
        },
        bottom: { 
            units: 4,
            size: function() { 
                return (np.Grid.unit * this.units)||0;
            }
        },
        right: { 
            units: 2,
            size: function() { 
                return (np.Grid.unit * this.units)||0;
            }
        }
    },
    
    col : { 
        units: 10,
        size: function() { 
            return (np.Grid.unit * this.units);
        },
        count: 8
    },
    
    computeColPixelWidth: function(colWidth) {
        return (np.Grid.unit * (colWidth * np.Grid.col.units)) + (np.Grid.gutter.size() * (colWidth - 1));
    },
    
    maxColumnUnits : function() { 
        return (np.Grid.col.units * np.Grid.col.count); 
    },
    
    maxGutterUnits : function() { 
        return (np.Grid.gutter.units * (np.Grid.col.count - 1)); 
    },
    
    liveUnits: function() {
        return (this.maxColumnUnits() + this.maxGutterUnits());
    },
    
    pageUnits: function() {
        return (this.liveUnits() + this.margin.left.units + this.margin.right.units);
    },
    
    commentsOK: true,
    
    notate: function(note) {
        return "\n\/* " + note + " *\/\n";
    },
    
    generateCSS : function(noComments) {
        if(noComments) np.Grid.commentsOK = false;
        var code = [];
        code.push(generateHeader());
        code.push(np.Grid.notate("The '.page-box' class is provided for you to attached to your outer wrapping page element.\n It provides the outer margin for your page layout.\n The '.page-body' element should hold your page contents."));
        code.push("\n");
        code.push(".page-box { width: " + (np.Grid.pageUnits() * np.Grid.unit)  + "px; padding-top: " + np.Grid.margin.top.size()+ "px; padding-bottom: " + np.Grid.margin.bottom.size() + "px; }\n");
        code.push(".page-body { width: " + (np.Grid.liveUnits() * np.Grid.unit) + "px; margin-left: " + np.Grid.margin.left.size() + "px; }\n");
        code.push(".page-body:after { content: '.'; display: block; height: 0; clear: both; visibility: hidden; }");
        code.push(np.Grid.notate("bottom margin"));
        code.push("\n");
        code.push(np.Grid.notate("Use the '.column' class below to prepare divs to act like columns.\n The result is 'inline-block like' behaviour"));
        code.push(np.Grid.notate("When combined with a '.colx#' or '.x#' class, the columns will sit next to each other.\n Otherwise, the column will take up as much room as it's content requires"));
        code.push(".column { float: left; display:inline; }\n");
        code.push(np.Grid.notate("Use the '.last' class to strip the extra gutter margin from the last column"));
        code.push(".last { margin-right: 0 !important; }\n");
        code.push(np.Grid.notate("Use the '.tier' class to create a block element with a height separation equal to the gutter width"));
        code.push(".tier { margin-bottom: " + np.Grid.unit + "px; }\n");
        code.push(generateColGrid());
        code.push(generateColPaddedGrid());
        code.push(generateTableGrid());
        code.push(generateRightSpacingGrid());
        code.push(generateLeftSpacingGrid());
        code.push(generateUnitGrid());
        code.push(generateLeftSpacingUnitGrid());
        code.push(generateRightSpacingUnitGrid());
        code.push(generateColHeightGrid());
        code.push(generateUnitHeightGrid());
        np.Grid.commentsOK = true;
        return code.join("");
        
        function generateHeader() {
            if(!np.Grid.commentsOK) return '';
            var code = [];
            code.push("\/***********************");
            code.push(" *");
            code.push(" * CSS generated by netProtozo Grid Generator");
            code.push(" * www.netprotozo.com/grid");
            code.push(" *");
            code.push(" * unit =  " + np.Grid.unit + "px, column = " + np.Grid.col.units + " units, gutter = " + np.Grid.gutter.units + " unit(s), margin = " + np.Grid.margin.top.units + " " + np.Grid.margin.right.units + " " + np.Grid.margin.bottom.units + " " + np.Grid.margin.left.units + " unit(s)");
            code.push(" *");
            code.push(" == STRUCTURE: ========================");
            code.push(" * Page:   " + (np.Grid.pageUnits() * np.Grid.unit) + "px");
            code.push(" * Column: " + (np.Grid.unit * np.Grid.col.units) + "px (" + np.Grid.col.count + ")");
            code.push(" * Gutter: " + np.Grid.gutter.size() + "px");
            code.push(" * Margin: " + np.Grid.margin.top.size() + "px " + np.Grid.margin.right.size() + "px " + np.Grid.margin.bottom.size() + "px " + np.Grid.margin.left.size() + "px");
            code.push(" ======================================");
            code.push(" *");
            code.push(" ***********************\/\n\n");
            return code.join("\n");
        }
        
        function generateColGrid(){
            var code = [];
            
            code.push(np.Grid.notate("column units"));
            for(var i = 1; i < np.Grid.col.count; i++) {
                code.push(".colx" + i + " { width: " + np.Grid.computeColPixelWidth(i) + "px; margin-right: " + np.Grid.gutter.size() + "px;}");
            }
            code.push(".colx" + np.Grid.col.count + ",\n.colfull { width: " + np.Grid.computeColPixelWidth(np.Grid.col.count) + "px; overflow: hidden; }");
            code.push(".fullpage { width: " + (np.Grid.pageUnits() * np.Grid.unit) + "px;  }");
            code.push(".h-fullpage { height: " + ((np.Grid.maxColumnUnits()  + (np.Grid.margin.top.units + np.Grid.margin.bottom.units)) * np.Grid.unit)  + "px;  }");
            code.push("\n");
            
            return code.join("\n");
        }
        
        function generateColPaddedGrid(){
            var code = [];
            code.push(np.Grid.notate("Use these if you want padding instead of margin \nif you want to butt things against each other visually"));
            for(var i = 1; i < np.Grid.col.count; i++) {
                code.push(".colx" + i + "p { width: " + (np.Grid.computeColPixelWidth(i) + np.Grid.gutter.size())  + "px; padding-right: " + np.Grid.gutter.size() + "px;}");
            }
            code.push(".colx" + np.Grid.col.count + "p { width: " + np.Grid.computeColPixelWidth(np.Grid.col.count) + "px; overflow: hidden; }");
            code.push("\n");
            return code.join("\n");
        }
        
        function generateTableGrid(){
            var code = [];
            code.push(np.Grid.notate(".full_nopad is to keep your tables from breaking layouts \nWe don't trust 100% on tables"));
            for(var i = np.Grid.col.count; i > 0; i--) {
                code.push(".colx" + i + " .full_nopad { width: " + np.Grid.computeColPixelWidth(i)  + "px; }");
            }
            code.push("\n");
            return code.join("\n");
        }
        
        function generateRightSpacingGrid(){
            var code = [];
            code.push(np.Grid.notate("add space to the right of elements equal to column divisions"));
            for(var i = 1; i < np.Grid.col.count; i++) {
                code.push(".rt-colx" + i + " { margin-right: " + (np.Grid.computeColPixelWidth(i) + np.Grid.gutter.size()) + "px; }");
            }
            code.push("\n");
            return code.join("\n");
        }
        
        function generateLeftSpacingGrid(){
            var code = [];
            code.push(np.Grid.notate("add space to the left of elements equal to column divisions"));
            for(var i = 1; i < np.Grid.col.count; i++) {
                code.push(".lt-colx" + i + " { margin-left: " + (np.Grid.computeColPixelWidth(i) + np.Grid.gutter.size()) + "px; }");
            }
            code.push("\n");
            return code.join("\n");
        }
        
        function generateUnitGrid(){
            var code = [];
            code.push(np.Grid.notate("sub units \nsetting elements widths equal to grid divisions"));
            for(var i = 1; i < np.Grid.maxColumnUnits(); i++) {
                code.push(".x" + i + " { width: " + (np.Grid.unit * i)  + "px; }");
            }
            code.push("\n");
            return code.join("\n");
        }
        
        function generateLeftSpacingUnitGrid(){
            var code = [];
            code.push(np.Grid.notate("add space to the left of elements equal to grid divisions"));
            for(var i = 1; i < np.Grid.maxColumnUnits(); i++) {
                code.push(".lt-x" + i + " { margin-left: " + (np.Grid.unit * i)  + "px; }");
            }
            code.push("\n");
            return code.join("\n");
        }
        
        function generateRightSpacingUnitGrid(){
            var code = [];
            code.push(np.Grid.notate("add space to the right of elements equal to grid divisons"));
            for(var i = 1; i < np.Grid.maxColumnUnits(); i++) {
                code.push(".rt-x" + i + " { margin-right: " + (np.Grid.unit * i)  + "px; }");
            }
            code.push("\n");
            return code.join("\n");
        }
        
        function generateColHeightGrid(){
            var code = [];
            code.push(np.Grid.notate("setting elements heights equal to column divisions"));
            for(var i = 1; i <= np.Grid.col.count; i++) {
                code.push(".h-colx" + i + " { height: " + np.Grid.computeColPixelWidth(i)  + "px; }");
            }
            code.push("\n");
            return code.join("\n");
        }
        
        function generateUnitHeightGrid(){
            var code = [];
            code.push(np.Grid.notate("setting elements heights equal to unit divisions"));
            for(var i = 1; i <= np.Grid.maxColumnUnits(); i++) {
                code.push(".h-x" + i + " { height: " + (np.Grid.unit * i)  + "px; }");
            }
            code.push("\n");
            return code.join("\n");
        }
        
    },
    
    printCSS : function() {
        var codeBin = $("#css-code-bin"), gForm = document.gridform;
        
        gForm.unit.value = np.Grid.unit = 
            ((50 >= parseInt(gForm.unit.value)) && 
            (parseInt(gForm.unit.value) >= 2))? parseInt(gForm.unit.value) : np.Grid.unit;
            
        gForm.gutter.value = np.Grid.gutter.units  = 
            ((10 >= parseInt(gForm.gutter.value)) && 
            (parseInt(gForm.gutter.value)>= 0))? parseInt(gForm.gutter.value) : np.Grid.gutter.units;
            
        gForm.colunits.value = np.Grid.col.units = 
            ((160 >= parseInt(gForm.colunits.value)) &&
            (parseInt(gForm.colunits.value) >= 1))? parseInt(gForm.colunits.value) : np.Grid.col.units;
            
        gForm.colcount.value = np.Grid.col.count = 
            ((20 >= parseInt(gForm.colcount.value)) && 
            (parseInt(gForm.colcount.value) >= 1))? parseInt(gForm.colcount.value) : np.Grid.col.count;
            
        gForm.margintopunits.value = np.Grid.margin.top.units = 
            ((20 >= parseInt(gForm.margintopunits.value)) && 
            (parseInt(gForm.margintopunits.value)>= 0))? parseInt(gForm.margintopunits.value) : np.Grid.margin.top.units;
            
        gForm.marginrightunits.value = np.Grid.margin.right.units = 
            ((20 >= parseInt(gForm.marginrightunits.value)) && 
            (parseInt(gForm.marginrightunits.value)>= 0))? parseInt(gForm.marginrightunits.value) : np.Grid.margin.right.units;
            
        gForm.marginbtmunits.value = np.Grid.margin.bottom.units = 
            ((20 >= parseInt(gForm.marginbtmunits.value)) && 
            (parseInt(gForm.marginbtmunits.value) >= 0))? parseInt(gForm.marginbtmunits.value) : np.Grid.margin.bottom.units;
            
        gForm.marginleftunits.value = np.Grid.margin.left.units = 
            ((20 >= parseInt(gForm.marginleftunits.value)) && 
            (parseInt(gForm.marginleftunits.value) >= 0))? parseInt(gForm.marginleftunits.value) : np.Grid.margin.left.units;
            
        codeBin.val(np.Grid.generateCSS());
    },
    
    generateGrid : function() {
        var code = [];
        $("#h-grid").html(generateLeftToRightGrid());
        $("#v-grid").html(generateTopToBottomGrid());
        $("#c-grid").html(generateColumns());
        
        function generateLeftToRightGrid() {
            var code = [], 
                gridUnits = np.Grid.pageUnits(),
                unitWidth = (np.Grid.unit - 1),
                gridHeight = ((np.Grid.maxColumnUnits() + (np.Grid.margin.top.units + np.Grid.margin.bottom.units)) * np.Grid.unit);
            for (var i=0; i < gridUnits; i++) {
                code.push('<div class="unit-col column" style="height:' + gridHeight + 'px; width:' + unitWidth + 'px;"></div>');
            }
            return code.join("");
        }
        
        function generateTopToBottomGrid() {
            var code = [],
                gridUnits = np.Grid.maxColumnUnits()  + (np.Grid.margin.top.units + np.Grid.margin.bottom.units),
                unitHeight = (np.Grid.unit) - 1,
                gridWidth = (np.Grid.pageUnits() * np.Grid.unit);

            for (var i=0; i < gridUnits; i++) {
                code.push('<div class="unit-row" style="height:' + unitHeight + 'px; width:' + gridWidth + 'px;"></div>');
            }
            return code.join("");
        }
        
        function generateColumns() {
            var code = [], 
                colWidth = (np.Grid.col.size() - 1),
                gridColHeight = ((np.Grid.maxColumnUnits()) * np.Grid.unit),
                gridMarginHeight = np.Grid.margin.top.size() + np.Grid.margin.bottom.size(),
                gridMarginWidth = np.Grid.margin.left.size() + np.Grid.margin.right.size(), 
                gridWidth = (np.Grid.pageUnits() * np.Grid.unit);
            
            code.push('<div style="padding-top:' + np.Grid.margin.top.size() + 'px; width:' + gridWidth + 'px; padding-bottom: '+np.Grid.margin.bottom.size()+'px;" class="grid-margin column">');
            code.push('<div style="margin-left:' + (np.Grid.margin.left.size()-1 ) + 'px;" class="column column-bin">');
            for (var i=0; i < np.Grid.col.count; i++) {
                code.push('<div style="height:' + gridColHeight + 'px; width:' + colWidth + 'px;" class="grid-col column g-colx1');
                if((i+1) == np.Grid.col.count) {
                    code.push(' last');
                }
                code.push('"></div>');
            }
            code.push('</div></div>');
            return code.join("");
        }
    },
    
    printGrid : function() {
        np.Grid.generateGrid()
    },
    
    update: function() {
        var code=[], rawsheet = [], newcss, cssrules;

        if(!$("head #generated-style")[0]) {
            newcss = document.createElement("style");
            newcss.type="text/css";
            newcss.media="all";
            newcss.id="generated-style";
            document.getElementsByTagName("head")[0].appendChild(newcss);   
        }
        newcss = document.styleSheets[1];
        
        np.Grid.printCSS();

        rawsheet.push(".g-colx1 { width: " + np.Grid.computeColPixelWidth(1) + "px; margin-right: " + (np.Grid.gutter.size()-1) + "px;}\n");
        rawsheet.push("#grid-ruler-left { height: " + ((np.Grid.maxColumnUnits()  + (np.Grid.margin.top.units + np.Grid.margin.bottom.units)) * np.Grid.unit)  + "px; }\n");
        rawsheet.push("#grid-ruler-top {width: " + (np.Grid.pageUnits() * np.Grid.unit)  + "px; }\n");
        rawsheet.push("#grid-code-bin {width: " + ((np.Grid.pageUnits() * np.Grid.unit) + 10)   + "px; }\n");
        rawsheet.push(np.Grid.generateCSS(true));
      
        if(newcss.rules) { //IE
            
            cssrules = rawsheet.join("").split("}");
            
            for(i=cssrules.length-2;i>=0;i--) {
                newrule = cssrules[i].split("{");
                newcss.addRule(newrule[0],newrule[1])
            }
        }
        else { //Firefox etc
        
            if($("head #generated-style").length == 0) {
                $("head").append("<style id='generated-style'></style>");
            }
            $("head #generated-style").empty().append(rawsheet.join(""));
            
        }
        
        $(".display-pnl").hide();
        np.Grid.printGrid();
        $(".display-pnl").show();
                
        code.push("<h1>" + (np.Grid.pageUnits() * np.Grid.unit) + "px</h1><p>page width</p><br/>");
        code.push("<h1>" + (np.Grid.liveUnits() * np.Grid.unit) + "px</h1><p>live area</p><br/>");
        code.push("<h1>"  + (np.Grid.unit * np.Grid.col.units) + "px ");
        code.push("("  + np.Grid.col.count + ")</h1><p>columns</p><br/>");
        code.push("<h1>" + np.Grid.gutter.size() + "px</h1><p>gutter</p><br/>");
        code.push("<h1>" + np.Grid.margin.top.size() + "px " + np.Grid.margin.right.size() + "px " + np.Grid.margin.bottom.size() + "px " + np.Grid.margin.left.size() + "px</h1><p>margins</p><br/>");
        
        $("#preamble").hide();
        $("#grid-data").html(code.join(""))
    }
    
}