﻿//variable to store hidden frame
var printingHiddenFrame;

//on load, create a hidden frame for printing the map
dojo.addOnLoad(function() {
    //console.debug("creating the printing stuff");
    printingHiddenFrame = document.createElement("iframe");
    printingHiddenFrame.src = "hiddenframe.html";
    dojo.style(printingHiddenFrame, "display", "none");
    dojo.body().appendChild(printingHiddenFrame);
    //console.debug("finised creating the printing stuff");
});


//dojo.require("com.js.printing.PrintableMap");
//dojo.require("com.js.printing.utils");

//serialize map state into JSON
// {
//   extent: <Object, { xmin, ymin, xmax, ymax, spatialReference }>,
//   layers: <Object[], layer JSON>,
//   graphics: <Object[], { geometry, symbol, attributes, template }>
// }
//function getMapState(m) {
//    var layerStates = [], graphicsState = [], graphics = m.graphics.graphics;

//    //serialize each layer's state
//    dojo.forEach(m.layerIds, function(layerId) {
//        layerStates.push(getLayerState(m.getLayer(layerId)));
//    });

//    //serialize graphics from last to first to retain graphics drawing order
//    for (var i = graphics.length - 1; i >= 0; i--) {
//        graphicsState.push(graphics[i].toJson());
//    };

//    return {
//        extent: m.extent.toJson(),
//        layers: layerStates,
//        graphics: graphicsState
//    };
//}

//return layer state as JSON
// {
//   id: <String>,
//   type: <String, class name>,
//   url: <String>,
//   visible: <Boolean>,
//   opacity: <Number>,
//   layerDefs: <String[], id:def>,
//   layers: <Number[]>
// }
//function getLayerState(layer) {
//    return {
//        id: layer.id,
//        type: layer.declaredClass,
//        url: layer.url,
//        visible: layer.visible,
//        opacity: layer.opacity,
//        layerDefs: layer.layerDefinitions,
//        layers: layer.visibleLayers
//    };
//}


function showPrintingPanel() {


    var s = [];
    //
    // The Following code is for the Original Print Page...
    // MVA- 10/5/2009 - Altered this print page due to IPrism blocking calls to REST API.
//    s.push("<table border=\"0\" width=\"100%\" cellpadding=\"0\" cellspacing=\"0\">");
//    s.push("<tbody><tr>");
//    s.push("<td colspan=\"2\" class=\"Bar\"><b>PRINT LAYOUT:</b></td></tr><tr>");
//    s.push("<td colspan=\"2\">&nbsp;</td></tr>");
//    s.push("<tr><td colspan=\"2\" class=\"Row1\" align=\"left\" valign=\"top\">TITLE:</td></tr>");
//    s.push("<tr><td colspan=\"2\" align=\"left\" valign=\"top\"><input id=\"layout_title\" size=\"20\" style=\"font-size: x-small;\"></td></tr>");
//    s.push("<tr><td colspan=\"2\">&nbsp;</td></tr>");
//    s.push("<tr><td colspan=\"2\" class=\"Row1\" align=\"left\" valign=\"top\">PAPER SIZE:</td></tr>");
//    s.push("<tr><td colspan=\"2\" align=\"left\" valign=\"top\"><select id=\"layout_paper\"><option value=\"LETTER\">Letter (8.5 inches X 11 inches)</option><option value=\"LETTERR\">Letter (11 inches X 8.5 inches)</option><option value=\"LEGAL\">Legal (8.5 inches X 14 inches)</option><option value=\"LEGALR\">Legal (14 inches X 8.5 inches)</option><option value=\"TABLOID\">Tabloid (11 inches X 17 inches)</option><option value=\"ANSI-A\">ANSI A (8.5 inches X 11 inches)</option><option value=\"ANSI-AR\">ANSI A (11 inches X 8.5 inches)</option><option value=\"ANSI-B\">ANSI B (11 inches X 17 inches)</option><option value=\"ANSI-BR\">ANSI B (17 inches X 11 inches)</option><option value=\"ANSI-C\">ANSI C (17 inches X 22 inches)</option><option value=\"ANSI-CR\">ANSI C (22 inches X 17 inches)</option><option value=\"ANSI-D\">ANSI D (22 inches X 34 inches)</option><option value=\"ANSI-DR\">ANSI D (34 inches X 22 inches)</option><option value=\"ANSI-E\">ANSI E (34 inches X 44 inches)</option><option value=\"ANSI-ER\">ANSI E (44 inches X 34 inches)</option><option value=\"ARCH-C\">ARCH C (18 inches X 24 inches)</option><option value=\"ARCH-CR\">ARCH C (24 inches X 18 inches)</option><option value=\"ARCH-D\">ARCH D (24 inches X 36 inches)</option><option value=\"ARCH-DR\">ARCH D (36 inches X 24 inches)</option><option value=\"ARCH-E\">ARCH E (36 inches X 48 inches)</option><option value=\"ARCH-ER\">ARCH E (48 inches X 36 inches)</option><option value=\"ARCH-E1\">ARCH E1 (30 inches X 42 inches)</option><option value=\"ARCH-E1R\">ARCH E1 (42 inches X 30 inches)</option></select></td></tr>");

//    s.push("<tr><td colspan=\"2\">&nbsp;</td></tr><tr><td colspan=\"2\" class=\"Row1\" align=\"left\" valign=\"top\">MAP LEGEND:</td></tr>");
//    s.push("<tr><td colspan=\"2\" align=\"left\" valign=\"top\"><input id=\"layout_legend_yes\" name=\"legend\" value=\"YES\" type=\"radio\"><font size=\"1\" face=\"Arial\"> YES</font><input id=\"layout_legend_no\" name=\"legend\" checked=\"checked\" value=\"NO\" type=\"radio\"><font size=\"1\" face=\"Arial\"> NO</font></td></tr>");
//    s.push("<tr><td colspan=\"2\">&nbsp;</td></tr><tr><td colspan=\"2\" class=\"Row1\" align=\"left\" valign=\"top\" style=\"font-style:italic;font-weight:bold;\">Note the below items change the current map:</td></tr>");  

//    // zoom to scale function
//    s.push("<tr><td colspan=\"2\">&nbsp;</td></tr><tr><td colspan=\"2\" class=\"Row1\" align=\"left\" valign=\"top\">SCALE (optional):</td></tr>");
//    s.push("<tr><td colspan=\"2\" align=\"left\" valign=\"top\">1 inch = <input id=\"layout_scale\" size=\"6\" style=\"font-size: x-small;\"> feet  <img src=\"images/blank.gif\" alt='' />");
//    s.push("<img src=\"Images/blank.gif\" alt=\"\" />   <input type=\"image\" style=\"vertical-align:bottom;\" onclick=\"doZoomScale_click('layout_scale');\" src=\"images/button-zoom.jpg\"/>");
//    s.push("</td></tr>");
//    s.push("<tr><td colspan=\"2\">&nbsp;</td></tr><tr>");
//    
//    // label parcel function
//    // s.push("<td colspan=\"2\" class=\"Row1\" align=\"left\" valign=\"top\">LABEL PARCELS BY (optional):</td></tr>");
//    // s.push("<tr><td colspan=\"2\" align=\"left\" valign=\"top\"><select id=\"layout_labelfield\"><option value=\"\"> </option><option value=\"PARCEL_ID\">Parcel ID</option><option value=\"OWNER\">Owner Name</option><option value=\"DEED\">Deed Book and Page</option><option value=\"SALES_DATE\">Most Recent Sale Date</option><option value=\"SALES_PRIC\">Most Recent Sale Amount</option><option value=\"TOT_VAL\">Property Value</option></select></td></tr>");


//    // button
//    s.push("<tr><td colspan=\"2\">&nbsp;</td></tr>");
//    s.push("<tr><td colspan=\"2\" align=\"center\" valign=\"top\"><a href=\"#\"   onmousedown=\"doLayout()\"><img src=\"images/button-preview-map.jpg\" border=\"0\"></a></td></tr>");
    //    s.push("</tbody></table>");



//    s.push("<table border=\"0\" width=\"100%\" cellpadding=\"0\" cellspacing=\"0\">");
//    s.push("<tbody><tr>");
//    s.push("<td colspan=\"2\" class=\"Bar\"><b>PRINT LAYOUT:</b></td></tr><tr>");
//    s.push("<tr><td colspan=\"2\" class=\"Row1\" align=\"left\" valign=\"top\">TITLE:</td></tr>");
//    s.push("<tr><td colspan=\"2\" align=\"left\" valign=\"top\"><input id=\"layout_title\" size=\"20\" style=\"font-size: x-small;\"></td></tr>");
//    s.push("<tr><td colspan=\"2\">&nbsp;</td></tr>");
//    s.push("<tr><td colspan=\"2\" class=\"Row1\" align=\"left\" valign=\"top\">MAP LEGEND:</td></tr>");
//    s.push("<tr><td colspan=\"2\" align=\"left\" valign=\"top\"><input id=\"layout_legend_yes\" name=\"legend\" value=\"YES\" type=\"radio\"><font size=\"1\" face=\"Arial\"> YES</font><input id=\"layout_legend_no\" name=\"legend\" checked=\"checked\" value=\"NO\" type=\"radio\"><font size=\"1\" face=\"Arial\"> NO</font></td></tr>");
//    s.push("<tr><td colspan=\"2\">&nbsp;</td></tr><tr>");

//    // button
//    s.push("<tr><td colspan=\"2\">&nbsp;</td></tr>");
//    s.push("<tr><td colspan=\"2\" align=\"center\" valign=\"top\"><a href=\"#\"   onmousedown=\"doLayout_PDF()\"><img src=\"images/button-print.jpg\" border=\"0\"></a></td></tr>");
//    s.push("</tbody></table>");

//       
//    dojo.byId("PRINT").innerHTML = s.join("");
    
    dojo.byId("printmessage").innerHTML = "";

}

function doLayout() {


    try {

        var title = dojo.byId("layout_title").value;
        var paper = dojo.byId("layout_paper").value;
        var legend = dojo.byId("layout_legend_yes").checked;
        var scale = dojo.byId("layout_scale").value;
        //var labelBy = dojo.byId("layout_labelfield").value;
        var showLegend = true;

        if (legend == false)
            showLegend = false;

       
        var width = 5.9;
        var height = 9.4;


        switch (paper) {
            case "LETTER":
                // 8.5 by 11
                // Width = 5.9 (8.5 inches minus 2.1 inches for top and bottom margins and minus .5 inch for title)
                // Height = 9.4 (11 inches minus 2.1 inches for left and right margins)
                width = 5.9
                height = 9.4
                break;
            case "LETTERR":
                width = 9.4
                height = 5.9
                break;
            case "LEGAL":
                width = 8.5
                height = 14
                break;
            case "LEGALR":
                width = 14
                height = 8.5
                break;
            case "TABLOID":
                // 11 by 17
                width = 8
                height = 15
                break;
            case "ANSI-A":
                width = 8.5
                height = 11
                break;
            case "ANSI-AR":
                width = 11
                height = 8.5
                break;
            case "ANSI-B":
                width = 11
                height = 17
                break;
            case "ANSI-BR":
                width = 17
                height = 11
                break;
            case "ANSI-C":
                width = 17
                height = 22
                break;
            case "ANSI-CR":
                width = 22
                height = 17
                break;
            case "ANSI-D":
                width = 22
                height = 34
                break;
            case "ANSI-DR":
                width = 34
                height = 22
                break;
            case "ANSI-E":
                width = 34
                height = 44
                break;
            case "ANSI-ER":
                width = 44
                height = 34
                break;
            case "ARCH-C":
                width = 18
                height = 24
                break;
            case "ARCH-CR":
                width = 24
                height = 18
                break;
            case "ARCH-D":
                width = 24
                height = 36
                break;
            case "ARCH-DR":
                width = 36
                height = 24
                break;
            case "ARCH-E":
                width = 36
                height = 48
                break;
            case "ARCH-ER":
                width = 48
                height = 36
                break;
            case "ARCH-E1":
                width = 30
                height = 42
                break;
            case "ARCH-E1R":
                width = 42
                height = 30
                break;
        }

        var mWidth = width * 96
        var mHeight = height * 96
        var legHeight = 0;
        var legWidth = 0;

        if (legend) {
            switch (paper) {
                case "LETTER", "LETTERR", "LEGAL", "LEGALR", "TABLOID", "ANSI-A", "ANSI-AR":
                    mWidth = width * 96 * .75
                    mHeight = height * 96
                    legWidth = width * 96 * .25
                    legHeight = height * 96
                    break;
                default:
                    var twidth = width - 2
                    width = twidth
                    mWidth = width * 96
                    var theight = height - 2
                    height = theight
                    mHeight = height * 96
                    legWidth = 2 * 96
                    legHeight = mHeight
                    break;
            }
        }

//        var state = {
//            title: title,
//            width: mWidth,
//            height: mHeight,
//            showlegend: showLegend,
//            legendwidth: legWidth,
//            legendheight: legHeight,
//            map: getMapState(map)
        //        }

        mapState = getMapState(map);


        var state = {
            title: title,
            width: mWidth,
            height: mHeight,
            showlegend: showLegend,
            legendwidth: legWidth,
            legendheight: legHeight,
            layers: mapState.layers,
            extent: mapState.extent
        }
//        var iframeDocument = dojo.isIE ? printingHiddenFrame.contentWindow.document : printingHiddenFrame.contentDocument;
//        iframeDocument.getElementById("PrintMapState").value = dojo.toJson(state);
        //        iframeDocument.getElementById("PrintMapForm").submit();

        //send request to mergeAndOutput.php, force proxy use


        var printMap = new com.js.printing.PrintableMap("./PrintArcObjectsMap.ashx", { layers: state.layers });

        // calculate the scale...
        var scale = com.js.printing.CalculatePrintMapScale(map)
        
     
     // args
     //   extent, width, height, callback
        printMap.getImageUrl(state.extent, mWidth, mHeight,scale, function(response) {
            console.debug(response);
            //alert(response);
        });
     

    } catch (Error) {

        alert("There was an error while attempting to print: " + Error.message);
    
    }

}


function doLayout_PDF() {

    //doPrint();
    //return false;

    var title = dojo.byId("layout_title").value;
    var legend = dojo.byId("layout_legend_yes").checked;

    var mapname = "landscape811";
    if (dojo.byId("layout_portriat").checked === true ) mapname="portriat811";
   
    
    //mapname = mapname + "_nolegend";
    if (legend === true)
        mapname = mapname + "_withlegend";
    else {mapname = mapname + "_nolegend";}   
    
    // calculate the scale...
    var scale = com.js.printing.CalculatePrintMapScale(map)
    var state = com.js.printing.getMapState(map);
    var printMap = new PrintableMap("http://gis.cravencountync.gov/giswebservices/PrintMapHandler.ashx");

    var selfeatures = com.js.printing.getSelectionState(map);

    // args
    //   extent, width, height, callback
    var params = {
        extent: state.extent,
        scale: scale,
        mapkey: mapname,
        title: title,
        height: -1,
        width: -1,
        graphics: selfeatures,
        layers: state.layers
    }
    console.debug(params);
        
    printMap.getImageUrl(params, function(response) {
        console.debug(response);
    });
     

}

// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
// update for Printing a single image
// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function doPrint() {

    var jsonData = "";
    
    var printWidth = 96 * 9.625;
    var printHeight = 96 * 6.125;
    
    var mapscale = esri.geometry.getScale(map.extent, map.width, map.spatialReference.wkid);
    //mapscale = mapscale * 12;
    var state = {
        map: getMapState(map),
        height: printHeight,
        width: printWidth,
        scale: mapscale,
        printExtent: getPrintExtent(map, printWidth, printHeight)
    };

    if (checkGraphicExtent(printWidth, printHeight)) {
        var iframeDocument = dojo.isIE ? printingHiddenFrame.contentWindow.document : printingHiddenFrame.contentDocument;
        iframeDocument.getElementById("appState2").value = dojo.toJson(state);
        iframeDocument.getElementById("printForm").submit();
    } else {
        var idHandle = dojo.connect(map, "onExtentChange", function() {
            dojo.disconnect(idHandle);
            doPrint();
        });
        map.centerAndZoom(map.extent.getCenter(), 2);       
    }
}


function checkGraphicExtent(printWidth, printHeight) {
    var origGraphic = map.graphics.graphics[0];
    if (origGraphic == null)
        return true;
    else {
        var centerPt = map.extent.getCenter();
        var screenCenter = map.toScreen(centerPt);

        var deltaX = printWidth / 2;
        var deltaY = printHeight / 2;

        var urPt1 = new esri.geometry.Point((screenCenter.x + deltaX), (screenCenter.y + deltaY));
        var ulPt1 = new esri.geometry.Point((screenCenter.x - deltaX), (screenCenter.y + deltaY));
        var llPt1 = new esri.geometry.Point((screenCenter.x - deltaX), (screenCenter.y - deltaY));
        var lrPt1 = new esri.geometry.Point((screenCenter.x + deltaX), (screenCenter.y - deltaY));

        var urPt = map.toMap(urPt1);
        var ulPt = map.toMap(ulPt1);
        var llPt = map.toMap(llPt1);
        var lrPt = map.toMap(lrPt1);

        var points = [];
        points.push(urPt);
        points.push(ulPt);
        points.push(llPt);
        points.push(lrPt);
        points.push(urPt);

        var polygon = new esri.geometry.Polygon(new esri.SpatialReference({ wkid: 2264 }));
        polygon.addRing(points);

        if (origGraphic.geometry.getExtent().getWidth() > polygon.getExtent().getWidth()) { return false; }
        else { return true; }

    }

}

function getPrintExtent(m, printWidth, printHeight) {

    var centerPt = m.extent.getCenter();
    var screenCenter = m.toScreen(centerPt);

    var deltaX = printWidth / 2;
    var deltaY = printHeight / 2;

    var urPt1 = new esri.geometry.Point((deltaX + screenCenter.x), (screenCenter.y - deltaY));
    var llPt1 = new esri.geometry.Point((screenCenter.x - deltaX), (screenCenter.y + deltaY));

    var urPt = m.toMap(urPt1);
    var llPt = m.toMap(llPt1);

    var offsetx = llPt1.x;
    var offsety = urPt1.y;

    return { xmin: llPt.x, ymin: llPt.y, xmax: urPt.x, ymax: urPt.y, offsetx: offsetx, offsety: offsety };
}

function getMapState(m) {
    var layerStates = [], graphicsState = [], svgState = [];
    //serialize each layer's state
    dojo.forEach(m.layerIds, function(layerId) {
        var gl = m.getLayer(layerId);
        if (gl.visible)
            layerStates.push(getLayerState(gl));
    });

    // first add the main graphic layer to the map...
    graphics = m.graphics.graphics;
    for (var i = graphics.length - 1; i >= 0; i--) {

        try {
            var g = graphics[i];
            if (g.geometry != null) {
                var svg = esri.geometry.toScreenGeometry(m.extent, m.width, m.height, g.geometry);
                var gclone = new esri.Graphic(svg, g.symbol);
                graphicsState.push(gclone.toJson());
            }
        } catch (Error) {
            console.warn("error serializing graphic...", Error);
        }

    };


    var graphicLayers = m.graphicsLayerIds;
    dojo.forEach(graphicLayers, function(layerId) {
        var gl = m.getLayer(layerId);
        if (gl != null) {
            //serialize graphics from last to first to retain graphics drawing order
            graphics = gl.graphics;
            if (gl.visible) {
                for (var i = graphics.length - 1; i >= 0; i--) {
                    try {
                        var g = graphics[i];
                        if (g.geometry != null) {
                            var svg = esri.geometry.toScreenGeometry(m.extent, m.width, m.height, g.geometry);
                            var gclone = new esri.Graphic(svg, g.symbol);
                            graphicsState.push(gclone.toJson());
                        }
                    } catch (Error) {
                        console.warn("error serializing graphic...", Error);
                    }
                };
            }
        }
    });



    return {
        extent: m.extent.toJson(),
        layers: layerStates,
        graphics: graphicsState
    };
}

function getLayerState(layer) {
    return {
        id: layer.id,
        type: layer.declaredClass,
        url: layer.url,
        visible: layer.visible,
        opacity: layer.opacity,
        layerDefs: layer.layerDefinitions,
        layers: layer.visibleLayers
    };
}



dojo.declare("PrintableMap", null, {

    url: null,
    layers: null,
    mapExtent: null,
    graphics: null,

    workingHTML: "<div style=\"margin:20px 7px 7px; height: 50px; text-align:center;font-size:1.2em; font-weight:bold;\"><p><img src=\"images/pleasewait.gif\" alt=\"please wait\"/></p><p>Generating Map</p></div>",


    //constructor for layer with custom required option: layers, extent
    constructor: function(url, options) {

        this.loaded = true;
        this.url = url;
    },

    //call mergeAndOutput.*, pass request JSON.
    //process response JSON and return image url
    getImageUrl: function(params, callback) {
        try {
            var layersJson = [], layerJson;

            this.graphics = params.graphics;
            this.layers = params.layers;

            dojo.forEach(this.layers, function(layer) {
                if (layer.visible) {
                    layerJson = { id: layer.id, url: layer.url, format: (layersJson.length == 0 ? "jpg" : "png"), opacity: layer.opacity };

                    if (layer.layers) {
                        layerJson.layers = layer.layers.join(",");
                    }
                    if (layer.layerDefs) {
                        var defs = [];
                        dojo.forEach(layer.layerDefs, function(def, index) {
                            if (def) {
                                defs.push(index + ":" + def);
                            }
                        });
                        layerJson.layerDefs = defs.join(";");
                    }

                    layersJson.push(dojo.toJson(layerJson));
                }
            });

            //request JSON
            var json = {
                scale: params.scale,
                width: map.width,
                height: map.height,
                extent: dojo.toJson(params.extent),
                layers: layersJson,
                title: params.title,
                mapkey: params.mapkey,
                features: this.graphics
            };

            console.debug(this.graphics);

            dojo.byId("printmessage").innerHTML = this.workingHTML;

            esri.request({
                url: this.url,
                postData: dojo.toJson(json),
                handleAs: "json",
                load: function(response, io) {
                    console.debug(response);

                    if (response.href != undefined) 
                        dojo.byId("printmessage").innerHTML = "<p><a target=\"_blank\" href=\"" + response.href + "\"/>Click here for your Map</a></p>";
                    else    
                        dojo.byId("printmessage").innerHTML = "<p>An Error occurred while processing your request...</p><p>" + ex.message + "</p>";

                },
                error: function(ex) {
                    dojo.byId("printmessage").innerHTML = "<p>An Error occurred while processing your request...</p><p>" + ex.message + "</p>";
                }
            }, true);


            //           var iframeDocument = dojo.isIE ? printingHiddenFrame.contentWindow.document : printingHiddenFrame.contentDocument;
            //           iframeDocument.getElementById("PrintMapState").value = dojo.toJson(json);
            //           iframeDocument.getElementById("PrintMapForm").submit();


        } catch (err) {
            dojo.byId("printmessage").innerHTML = "<p>An Error occurred while processing your request...</p><p>" + err.message + "</p>";
        }
    },

    onError: function(err) {

        alert("An Error Occurred in the application");

        alert(err.message);

    }
});


dojo.provide("com.js.printing.utils");

com.js.printing.CalculatePrintMapScale = function(/*map*/map) {
    var xmin = map.extent.xmin;
    var ymin = map.extent.ymin;
    var xmax = map.extent.xmax;
    var ymax = map.extent.ymax;

    var dpi = 96;
    var w = map.width / dpi;
    var h = map.height / dpi;

    var mapH = map.extent.getHeight();
    var mapW = map.extent.getWidth();

    var distanceOnMap = Math.sqrt((w * w) + (h * h));
    var distanceOnGround = Math.sqrt((mapH * mapH) + (mapW * mapW));
    var scale = distanceOnGround / distanceOnMap;
    scale = scale * 12;
    return scale;
};


com.js.printing.getMapState = function(m) {
    var layerStates = [], graphicsState = [], graphics = m.graphics.graphics;

    //serialize each layer's state
    dojo.forEach(m.layerIds, function(layerId) {
        layerStates.push(com.js.printing.getLayerState(m.getLayer(layerId)));
    });

    // first add the main graphic layer to the map...
    graphics = m.graphics.graphics;
    for (var i = graphics.length - 1; i >= 0; i--) {

        try {
            var g = graphics[i];
            if (g.geometry != null) {
                var gclone = new esri.Graphic(g.geometry, g.symbol);
                graphicsState.push(gclone.toJson());
            }
        } catch (Error) {
            console.warn("error serializing graphic...", Error);
        }

    };
    


    var graphicLayers = m.graphicsLayerIds;
    console.debug(graphicLayers);
    dojo.forEach(graphicLayers, function(layerId) {
        var gl = m.getLayer(layerId);
        console.debug(layerId);
        if (gl != null) {
            //serialize graphics from last to first to retain graphics drawing order
            graphics = gl.graphics;
            for (var i = graphics.length - 1; i >= 0; i--) {

                try {
                    var g = graphics[i];
                    //console.debug(g);
                    if (g.geometry != null) {
                        var gclone = new esri.Graphic(g.geometry, g.symbol);
                        graphicsState.push(gclone.toJson());
                    }
                } catch (Error) {
                    console.warn("error serializing graphic...", Error);
                }
            };
        }
    });
    
    
    return {
        extent: m.extent.toJson(),
        layers: layerStates,
        graphics: graphicsState
    };
};

com.js.printing.getLayerState = function(layer) {
    return {
        id: layer.id,
        type: layer.declaredClass,
        url: layer.url,
        visible: layer.visible,
        opacity: layer.opacity,
        layerDefs: layer.layerDefinitions,
        layers: layer.visibleLayers
    };
};

com.js.printing.getSelectionState = function(m) {

    var selected = [];

    var graphicLayers = m.graphicsLayerIds;
    dojo.forEach(graphicLayers, function(layerId) {
        var gl = m.getLayer(layerId);
        if (gl != null) {
            selected.push(com.js.printing.getGraphicSelectionState(gl));
            console.debug(com.js.printing.getGraphicSelectionState(gl));
        }
    });  // end dojo for looop

    return selected;
};

com.js.printing.getGraphicSelectionState = function(layer) {
    var ids = [];
    dojo.forEach(layer.graphics, function(g) {
        try {
            if (g.geometry != null) {
                if (g.attributes != undefined) {
                    if (g.attributes.OBJECTID != undefined) {
                        ids.push(g.attributes.OBJECTID);
                    }
                }
            }
        } catch (Error) { console.warn("error serializing graphic...", Error); }
    });  // end dojo for loop

    return { id: layer.id,
        visible: layer.visible,
        features: ids
    }
};
    