// Globals
content      = null;
currentlyShown = [null, null, null];
pages        = {};
galleries    = {};
hashHash     = {};
shippingCost = undefined;
galleryHtmls = {};
preloadList  = [];
preloader    = [];
loadedImages = [];

// Constants
GALLERY_NAMES = ["animals", "fantasy", "drawings", "originals"];
PAGE_BUTTONS = [null, "one", "two", "three", "four", "five", "six", "seven",
    "eight", "nine"];
GALLERY_NAME = {"news": "", "animals": " - Animals Gallery",
    "fantasy": " - Fantasy Gallery", "drawings": " - Drawings Gallery",
    "originals": " - Originals Gallery", "cart": " - My Shopping Cart",
    "info": " - Information"};
GALLERY_NAME2 = {"news": "", "animals": "Animals Gallery - ",
    "fantasy": "Fantasy Gallery - ", "drawings": "Drawings Gallery - ",
    "originals": "Originals Gallery - ", "cart": "My Shopping Cart - ",
    "info": "Information - "};
GALLERY_DESC = {"news": "Animals, monsters, fantasy, and drawings. Originals and prints in acrylic, marker, and colored pencil.",
    "animals": "Animals and anthropomorphic furries in acrylic, marker, and colored pencil. Originals and prints of amusing and beautiful creatures.",
    "fantasy": "Mythical and fantasy creatures in acrylic, marker, and colored pencil. Originals and prints of dragons, werewolves, gryphons, and gods.",
    "drawings": "Pencil sketches of animals, athropomorphic furries, mythical and fantasy creatures. Black and white drawings of dragons, werewolves, gryphons, and gods.",
    "originals": "Original paintings of animals, anthropomorphic furries, mythical and fantasy creatures for sale. Dragons, werewolves, gryphons, and gods in acrylic, marker, and colored pencil.",
    "cart": "",
    "info": "I am a Colorado artist specializing in animals and mythical creatures. I incorporate themes from many different cultures into my art."};
CART_CLASSES = ["hidden", "cart1", "cart2", "cart3", "cart4", "cart5", "cart6",
    "cart7", "cart8", "cart9", "cart10"];
VIEW_CMD = {"news": "FrontPage", "animals": "AnimalsGallery",
    "fantasy": "FantasyGallery", "drawings": "DrawingsGallery",
    "originals": "OriginalsGallery", "info": "InfoPage",
    "cart": "ShoppingCart"};

// Utility functions
function hashLength($hash) {
  var $count = 0;
  for (var $i in $hash) $count++
  return $count;
}

function plural($n, $singular, $plural) {
  if ($n == 1) return $n + $singular; else return $n + $plural;
}

function processLink($galleryName, $page, $link) {
    var $gallery = galleries[$galleryName];
    var $image = $link.find("img");

    // Gather the image link parts (gallery & filename)
    var $parts = $link.attr("href").split("/").slice(-3);

    var $hash = "#!gallery=" + $galleryName + "&page=" + $page + "&image=" +
        $parts[2];
    hashHash[$link.attr("href")] = $hash;

    // First image in the gallery?
    if (! $gallery) {
        $gallery = {
            name: $galleryName,
            images: new Array(),
            titles: new Array(),
            descriptions: new Array(),
            fnHash: new Object(),
            imageIndex: null,
            hashes: new Array()
        };
    }
    var $index = $gallery.images.length;

    // Add details about this item to the gallery
    $gallery.images.push($link.attr("href"));
    $gallery.titles.push($image.attr("title"));
    $gallery.descriptions.push($image.attr("alt"));
    $gallery.hashes.push($hash);

    // Save the image index
    $gallery.fnHash[$parts[2]] = $index;

    // Update the global (gag!) gallery object
    galleries[$galleryName] = $gallery;

    // Images on the first pages should be loaded immediately. Other URLs are
    // saved for future preloading.
    if ($page == 1) {
        var $img = new Image();
        $img.src = $image.attr("url");
        loadedImages.push($img);
    } else {
        if (!preloadList[$page]) preloadList[$page] = new Object();
        if (!preloadList[$page][$galleryName]) {
            preloadList[$page][$galleryName] =  new Array();
        }
        preloadList[$page][$galleryName].push($image.attr("url"));
    }
}

function parseGallery($index, $gallery) {
    // Create HTML for the gallery
    $gallery = $($gallery);
    var $galleryName = $gallery.attr("name");
    var $page = $gallery.attr("page");
    var $id = $galleryName + "_" + $page;
    var $html = $gallery.html();

    // Process all the image links in the gallery
    $($html).find("a").each(function($index, $link) {
        processLink($galleryName, $page, $($link)); });

    // Add the completed gallery page to the DOM
    galleryHtmls[$id] = $html;

    // Save a record of how many pages are in this gallery
    pages[$galleryName] = $page;
}

function getGalleryHtml($galleryName, $page) {
    var $html = $(galleryHtmls[$galleryName + "_" + $page] || "");
    $html.find("img").each(function ($index, $item) {
        var $img = $($item);
        $img.attr("src", $img.attr("url"));
    });

    // Replace the links' normal navigation with a click handler
    $html.find("a").click(function($event) {
        var $parts = $(this).attr("href").split("/").slice(-3);
        $event.preventDefault();
        $.bbq.pushState({image: $parts[2]});
    });

    return $html;
}

// Highlight (or un-highlight) a given gallery name link and page number
function highlightButtons($enable, $galleryName, $page) {
    if ($enable) {
        $("div#" + $galleryName + "1").addClass("highlight");
        $("a#" + PAGE_BUTTONS[$page] + "1").addClass("highlight");
    } else {
        $("div#" + $galleryName + "1").removeClass("highlight");
        // No need to unhighlight page number since the list will re-gen
    }
}

function showPage($galleryName, $page) {
    var $html = "";

    // Hide the current gallery
    if (currentlyShown[0] == "cart") {
        $("div#shopping_cart,div#cart").addClass("hidden");
        $("div#top_nav").removeClass("hidden");
    } else if ((currentlyShown[0] || "news") == "news") {
        $("body").removeClass("front");
        $("div#darknatasha,div#gallery_nav,div#news").addClass("hidden");
        $("img#page1,span#pages,div#bottom_nav").removeClass("hidden");
    } else if (currentlyShown[0] == "info") {
        $("div#darknatasha,div#info").addClass("hidden");
        $("img#page1,span#pages").removeClass("hidden");
    } else {
        $("div#images").html("");
        $("div#" + currentlyShown[0]).addClass("hidden");
        highlightButtons(false, currentlyShown[0], currentlyShown[1]);
    }

    // Build a page list
    for (var $i = 1; $i <= pages[$galleryName]; $i++) {
        $html += "<a id='" + PAGE_BUTTONS[$i] + "1' href='#!gallery=" +
            $galleryName + "&page=" + $i + "'><img src='images/blank.gif' " +
            "width='1' height='1' title='" + $i + "' /></a>";
    }
    $("span#pages").html($html);

    // Show the new gallery
    if ($galleryName == "cart") {
        $("div#shopping_cart,div#cart").removeClass("hidden");
        $("div#top_nav").addClass("hidden");
    } else if ($galleryName == "news") {
        $("body").addClass("front");
        $("div#darknatasha,div#gallery_nav,div#news").removeClass("hidden");
        $("img#page1,span#pages,div#bottom_nav").addClass("hidden");
    } else if ($galleryName == "info") {
        $("div#darknatasha,div#info").removeClass("hidden");
        $("img#page1,span#pages").addClass("hidden");
    } else {
        $("div#images").html(getGalleryHtml($galleryName, $page));
        $("div#" + $galleryName).removeClass("hidden");
        highlightButtons(true, $galleryName, $page);
    }
}

function onHashchange($event) {
    var $params = $.deparam(window.location.hash.substring(2));
    var $galleryName = $params["gallery"] || "news";
    var $page = parseInt($params["page"]) || 1;
    var $image = $params["image"];
    var $cart = $params["cart"];

    // If cart is specified in the URL, then this overrides any given gallery
    if ($cart) {
        $galleryName = "cart";

        // Cart command may be "show" or a number ("0", "1"...) to
        // indicate that we are viewing an image on the shopping cart.
        if (($cart == "show")) {
            updateCart($cart);
            $image = null;
        } else {
            $image = $cart;
            var $galleryObj = galleries[$galleryName];
            $galleryObj.imageIndex = parseInt($image);
        }
    } else {
        var $galleryObj = galleries[$galleryName];
        if ($galleryObj) $galleryObj.imageIndex = $galleryObj.fnHash[$image];
    }

    // Update which page we're seeing?
    if ((currentlyShown[0] != $galleryName) || (currentlyShown[1] != $page)) {
        showPage($galleryName, $page);
    }

    // At this point we may need to start showing an image, stop showing an
    // image, or change to a different image
    if ($image) {
        var $title = $galleryObj.titles[$galleryObj.imageIndex];

        document.title = "The Art of Dark Natasha - " + $title;
        $("div#seo h1").text($title + " - The Art of Dark Natasha");
        $("div#seo p#content").html($galleryObj.descriptions[$galleryObj.imageIndex]);

        if (currentlyShown[2]) {
            // Change images
            $.prettyPhoto._hideContent(function() {
                $.prettyPhoto.open($galleryObj); });
        } else {
            // Start showing an image
            $.prettyPhoto.open($galleryObj);
        }
        _gaq.push(["_trackEvent", VIEW_CMD[$galleryName],
            $galleryObj.images[$galleryObj.imageIndex]]);
    } else {
        // Set the gallery name
        document.title = "The Art of Dark Natasha" + GALLERY_NAME[$galleryName];
        $("div#seo h1").text(GALLERY_NAME2[$galleryName] +
            "The Art of Dark Natasha");
        $("div#seo p#content").text(GALLERY_DESC[$galleryName]);

        // Stop showing an image
        if (currentlyShown[2]) $.prettyPhoto.close();
        _gaq.push(["_trackEvent", VIEW_CMD[$galleryName], "Page"  + $page]);
    }

    currentlyShown = [$galleryName, $page, $image];
    if (preloadList[$page + 1] && preloadList[$page + 1][$galleryName]) {
        while (true) {
            var $url = preloadList[$page + 1][$galleryName].pop();
            if (! $url) break;
            var $img = new Image();
            $img.src = $url;
            loadedImages.push($img);
        }
        delete preloadList[$page + 1][$galleryName];
    }

    // Scroll to top
    window.scroll(0, 0);
}

function cartAdd() {
    var $image = $.bbq.getState("image");
    var $id = $image.split(".")[0];
    var $type = "print";
    if ($.bbq.getState("gallery") == "originals") {
        $type = "original";
    } else if (! content.find("item#" + $id + " choice#print").length) {
        $type = "matted";
    }
    var $sku = $id + "." + $type;
    var $hash = orderCookieToHash();
    $hash[$sku] = ($hash[$sku] || 0) + 1;
    hashToOrderCookie($hash);
    $.bbq.pushState({cart: "show"});
    _gaq.push(["_trackEvent", "AddToCart", $sku]);
}

// Check for a cart in the cookie list and convert it to an hash[sku.type]=qty
function orderCookieToHash() {
  var $retVal = {};
  var $cookieString = $.cookie("cart");

  // Is there a cart yet?
  if ($cookieString) {
    // Yes, iterate through each item (delimited with ";")
    $.each($cookieString.split(";"), function($index, $item) {
      // Each item is formatted as sku,qty
      var $components = $item.split(",");
      $retVal[$components[0]] = parseInt($components[1]);
    });
  }
  return $retVal;
}

// Take an hash[sku]=qty and save it in the shopping cart cookie
function hashToOrderCookie($hash) {
  var $temp = new Array();

  // Loop through each hash element
  $.each($hash, function($sku, $qty) {
    // Create a sku,qty entry
    $temp.push($sku + "," + $qty); });

  // Merge the items together (";" delimiter) and save in a cookie
  $.cookie("cart", $temp.join(";"), { expires: 30 });
}

// Update the shopping cart
function updateCart($cartCmd) {
    var $template = $("div#cart tr.hidden");
    var $hash = orderCookieToHash();
    var $numItems = hashLength($hash);
    var $cart = $("div#cart");
    var $totItems = 0;
    var $totCost = shippingCost;
    var $country = $("select#country");
    var $shipOpt = $("select#shipping");

    // Gallery object to display items in cart
    var $gallery = {
        name: "cart",
        images: new Array(), // full urls
        titles: new Array(),
        descriptions: new Array(),
        fnHash: new Array(), // {fn1.jpg: 0, fn2.jpg: 1, }
        imageIndex: null,
        hashes: new Array() // [#<current hash>&cart=0, ...1, ...2]
    };

    // Remove old content
    $cart.find("tr.dynamic").remove();

    // Loop through the shopping cart
    var $i = 0;
    $.each($hash, function($sku, $qty) {
        // Duplicate the template row
        var $skuParts = $sku.split(".");
        var $row = $($template.clone());
        $row.removeClass("hidden").addClass("dynamic");

        // Find the item in the catalog
        var $product = content.find("item#" + $skuParts[0]);
        var $choice = $product.find("choice#" + $skuParts[1]);
        var $costPer = Number($choice.attr("cost"));
        var $cost  = $qty * $costPer;
        var $galleryObj = $product.find("gallery");
        var $gName = $galleryObj.text();
        var $page = $galleryObj.attr("page");
        var $title = $product.find("title").text();
        var $state = $.bbq.getState();
        var $filename = $skuParts[0] + ".jpg";
        $state["cart"] = $i;
        var $href = $.param.fragment("", $state);
        $totItems += $qty;
        $totCost += $cost;

        // Save image details in a gallery
        $gallery.images.push($product.find("original").text());
        $gallery.titles.push($title);
        $gallery.descriptions.push($product.find("description").text());
        $gallery.fnHash[$filename] = $i;
        $gallery.hashes.push($href);

        // Populate the new row
        var $optSel = $row.find("select");
        $optSel.attr("id", $i);
        $i++;
        $row.find("td.qty").append($qty).find("input").attr({name: "quantity_" +
            $i, value: $qty});
        var $increase = $row.find(".increase");
        $increase.click(function($event) { adjustQty($event, $skuParts, +1); });
        if ($skuParts[1] == "original") $increase.addClass("faded");
        var $decrease = $row.find(".decrease");
        $decrease.click(function($event) { adjustQty($event, $skuParts, -1); });
        if ($qty == 1) $decrease.addClass("faded");
        $product.find("choice").each(function ($index, $choice) {
            $choice = $($choice);
            var $id = $choice.attr("id");
            var $html = "<option value='" + $id + "'>" +
                $choice.text() + "</option>";
            $optSel.append($html);
        });
        $optSel.val($skuParts[1]);
        $optSel.change(changeOption);
        $row.find("a.title").append($title).attr("href", $href);
        $row.find("a.gname").html($gName).attr("href", "#!gallery=" + $gName +
            "&page=" + $page);
        $row.find("td.description input").attr({name: "item_name_" + $i,
            value: $optSel.find(":selected").text() + ' of "' + $title + '"'});
        $row.find("td.cost").append("$" +
            $cost.toFixed(2)).find("input").attr({name: "amount_" + $i,
            value: $costPer});
        $row.find("img.remove").click(function($event) {
            removeItem($event, $sku); });

        // Add the new row
        $template.before($row);
    });
    galleries["cart"] = $gallery;

    // Shipping
    $i++;
    $("input#shipping").attr({name: "amount_" + $i, value: shippingCost});
    var $handling = $shipOpt.find("option:selected").text() + " shipping (" +
        $country.find("option:selected").text() + ")";
    $("input#handling").attr({name: "item_name_" + $i, value: $handling});

    // Skin the selects. We use a delay to give the page a moment to render.
    setTimeout(function() { $("select").select_unskin().select_skin(); }, 100);

    // Show totals
    $("div#cart td.qty.tally").html(plural($totItems, " item", " items"));
    if ($totCost) $("div#cart td.cost.tally").html("$" + $totCost.toFixed(2));

    // Empty cart?
    $cart.find("p#banner,p#empty,table,#checkout,div#doublecheck,div#thanks").removeClass("hidden");
    if ($numItems) {
        $cart.find("p#empty,div#thanks").addClass("hidden");
    } else {
        $cart.find("p#banner,table,#checkout,div#doublecheck,div#thanks").addClass("hidden");
    }
    showCart($numItems);
}

function changeOption($event) {
    var $select = $(this);
    var $cartItems = $.cookie("cart").split(";");
    var $replaceItem = $select.attr("id");
    var $newOpt = $select.find("option:selected").val();

    // Loop through each shopping cart item
    $.each($cartItems, function ($index, $item) {
        // Is this the item they changed?
        if ($index == $replaceItem) {
            // What was the original SKU?
            var $itemSplit = $item.split(",");
            var $skuSplit = $itemSplit[0].split(".");

            // Change to an original?
            if ($newOpt == "original") {
                // Yes, so only one is available
                $cartItems[$index] = $skuSplit[0] + ".original,1";
            } else {
                // No, maintain previous quantity
                $cartItems[$index] = $skuSplit[0] + "." + $newOpt + "," +
                    $itemSplit[1];
            }
        }
    });
    $.cookie("cart", $cartItems.join(";"), { expires: 30 });
    updateCart("show");
    _gaq.push(["_trackEvent", "UpdateItem", $newOpt]);
}

function adjustQty($event, $skuParts, $adj) {
    var $hash = orderCookieToHash();
    var $sku = $skuParts[0] + "." + $skuParts[1];
    $hash[$sku] += $adj;
    if ($skuParts[1] == "original") $hash[$sku] = 1;
    hashToOrderCookie($hash);
    updateCart("show");
    _gaq.push(["_trackEvent", "AdjustQty", $sku + "." + $hash[$sku]]);
}

function removeItem($event, $sku) {
    var $hash = orderCookieToHash();
    delete $hash[$sku];
    hashToOrderCookie($hash);
    updateCart("show");
    _gaq.push(["_trackEvent", "RemoveFromCart", $sku]);
}

function showCart($numItems) {
  var $img = $("img#cart");
  var $classNum = ($numItems < 10) ? $numItems : 10;

  $img.attr("title", plural($numItems, " item", " items") +
    " in your shopping cart").removeClass().addClass(CART_CLASSES[$classNum]);
}

function processNewsLink($link) {
    $link.click(function($event) {
        $event.preventDefault();
        $.bbq.pushState(hashHash[$link.attr("href")]);
    });
}

function changeCountry($event) {
    var $country = $("select#country");
    var $shipOpt = $("select#shipping");
    var $countryId = $country.val();

    // List shipping options
    $shipOpt.html("");
    content.find("shipping#" + $countryId +
        " choice").each(function ($index, $method) {
        $shipOpt.append("<option value='" + $($method).attr("rate") + "'>" +
            $($method).attr("method") + "</option>");
    });
    changeShipping($event);
//    _gaq.push(["_trackEvent", "SetCountry", $countryId]);
}

function changeShipping($event) {
    var $rate = $("select#shipping").val();
    if ($rate) {
        shippingCost = Number($rate);
        $("td#shipcost").html("$" + shippingCost.toFixed(2) + " *");
        $.cookie("shipping", $("select#country").val() + "," + $rate,
            { expires: 365 });
    }
    updateCart("show");
//    _gaq.push(["_trackEvent", "SetShipping", $rate]);
}

function onCheckout($event) {
    // Don't submit just yet!
    $event.preventDefault();

    // Submit the current cart to an extra tracking script. This will allow us
    // keep statistics on purchases for future reference. Note that these are
    // not "official purchases" yet. The customer could back out and not pay for
    // the items sent along to PayPal.
    $.post("purchase.php", {cart: $.cookie("cart")}, function ($xml) {
        $("div#cart form").submit(); });
    _gaq.push(["_trackEvent", "ShoppingCart", "CheckOut"]);

    // Clear out shopping cart so a returning customer won't see old items in it
    hashToOrderCookie( {} );
}

function onContent($xml) {
    content = $($xml);
    var $country = $("select#country");

    // List shipping options
    content.find("shipping").each(function ($index, $dest) {
        $country.append("<option value='" + $($dest).attr("id") + "'>" +
        $($dest).attr("country") + "</option>");
    });

    // Does user have a preferred country and shipping method?
    var $shipping = $.cookie("shipping") || "0,0";
    var $array = $shipping.split(",");
    $country.val($array[0]);
    changeCountry();
    $("select#shipping").val($array[1]);
    changeShipping();

    // Display the news
    var $news = $(content.find("news").html());
    $news.find("a.dupLink").each(function ($index, $link) {
        processNewsLink($($link)) });
    $("div#news").append($news);

    // Find all the galleries
    content.find("gallery").each(parseGallery);

    // Navigation is in the form of a hashchange event
    $(window).bind("hashchange", onHashchange);
    $(window).trigger("hashchange");

    // Fix "continue shopping" button
    $("a#continue").click(function($event) {
        $event.preventDefault();
        $.bbq.removeState("cart");
    });

    // Fix shopping cart button
    $("a#cart").click(function($event) {
        $event.preventDefault();
        $.bbq.pushState({cart: "show"});
    });

    // Fix email addresses
    $("a.email").each(function ($index, $a) {
        var $link = $($a);
        var $addr = $link.html() + "@darknatasha.com";
        $link.html($addr).attr("href", "mailto:" + $addr);
    });
    // Handle select change
    $("select#country").change(changeCountry);
    $("select#shipping").change(changeShipping);

    // Patch the checkout button
    $("a#checkout").click(onCheckout);

    // Update the number of items in the cart
    showCart(hashLength(orderCookieToHash()));
}

function onReady() {
    // Enable hashbang
    $.param.fragment.ajaxCrawlable(true);

    // Initialize prettyPhoto
    $.fn.prettyPhoto();

    // Load semi-dynamic content
    var $now = new Date();
    $.ajax({url: "content.xml?" + $now.getTime(), success: onContent,
        dataType: "html"});
}

