﻿// Copyright 2008 Jackson Fish Market LLC

var g_pageWidth = 1004;
var g_slVersion = "2.0.31005";  // SL 2.0 RTW

// Strings

var g_text = {
    en: {
        parserError: "Silverlight is having trouble starting the forest viewer. Sorry for the inconvenience!\n\nWe've seen this happen if you had a previous version of Silverlight installed.\nUsually it will work if you close the browser window and try again.",
        viewerError: "Oops...our forest viewer seems to be having difficulties.\nThe problem has been reported to our repair crew.\nWe're very sorry for the inconvenience.\n\nOften you just need to close the browser window and try again.",
        notEnoughQuiz: "We don't insist you fill out the whole quiz, but how about at least half of it?",
        quizAllGood: "Wow. You’re already doing a great job reducing your carbon footprint. If you still want to plant a virtual tree, just change one of your answers and take credit for things you’re already doing. You can also go to the home page and explore the forests to see other people’s trees.",
        noReminders: "We know it’s tough to change your routine, but we’d appreciate if you could select at least one commitment before we take you to plant your tree.",
        mailError: "Oops...we weren't able to send the mail for you. Sorry about that!"
    },
    fr: {
        parserError: "Silverlight a des difficultés à démarrer le navigateur. Nous nous excusons de la gêne occasionnée. Il est possible que vous aviez une version plus ancienne de Silverlight installée sur votre PC.  Fermez la fenêtre de votre navigateur et essayez de nouveau.",
        viewerError: "Oups...notre fenêtre d'affichage semble avoir des difficultés.\n\nNous avons transmis ces informations à notre équipe de réparation et nous nous excusons de la gêne occasionnée.\nEssayez de rafraîchir la page.",
        notEnoughQuiz: "Nous ne vous obligeons pas à remplir tout le quiz, mais voulez-vous essayer au moins la moitié?",
        quizAllGood: "Bravo. Vous faites déjà beaucoup pour réduire votre empreinte carbone. Si vous désirez toujours planter un arbre virtuel, veuillez simplement changer une de vos réponses. Vous pouvez également naviguer vers la page d'accueil et explorer les forêts pour voir les arbres d'autres personnes.",
        noReminders: "Nous comprenons qu'il est difficile de changer ses habitudes, mais voulons que vous vous engagiez à changer au moins une de ces routines avant que vous plantiez votre arbre.",
        mailError: "Oups… nous n'avons pas pu envoyer l'e-mail. Nous sommes vraiment désolés."
    },
    de: {
        parserError: "Silverlight hat Schwierigkeiten, die Ansicht des Waldes (Viewer) zu starten. Bitte entschuldigen Sie diese Unannehmlichkeit! Das Problem tritt häufig dann auf, wenn Anwender bereits eine ältere Version von Silverlight installiert haben. Normalerweise reicht es, wenn Sie den Webbrowser schließen und neu starten.",
        viewerError: "Es scheint, dass wir ein Problem mit der Ansicht des Waldes (Viewer) haben. Eine Fehlermeldung ist uns weitergeleitet worden. Bitte entschuldigen Sie die Unannehmlichkeiten. Vermutlich handelt es sich nur um ein kurzfristiges Problem. Bitte versuchen Sie daher die Webseite zu aktualisieren.",
        notEnoughQuiz: "Es ist nicht notwendig, dass Sie alle Fragen beantworten, aber es wäre schön, wenn Sie uns zumindest auf die Hälfte antworten würden.",
        quizAllGood: "Super! Sie leisten bereits einen guten Beitrag, um CO2 zu reduzieren. Falls Sie einen virtuellen Baum anpflanzen möchten, ändern Sie bitte eine Ihrer Antworten. Sie können aber auch auf unserer Homepage die Wälder erkunden und sich die Bäume anderer Teilnehmer ansehen.",
        noReminders: "Wir wissen, dass es schwer ist, Ihren Lebensgewohnheiten zu ändern. Aber wir wären Ihnen dankbar, wenn Sie zumindest eine Verpflichtung auswählen würden, ehe wir Sie zum Pflanzen eines Baumes weiterleiten.",
        mailError: "Entschuldigungen Sie ... wir konnten die E-Mail an Sie leider nicht absenden. Es tut uns leid!"
    },
    pl: {
        parserError: "Silverlight ma problem z uruchomieniem przeglądania lasu. Przepraszamy za niedogodności! Dzieje się tak, jeśli masz zainstalowaną starą wersję Silverlight. Rozwiązaniem problemu jest zamknięcie przeglądarki i uruchomienie jej na nowo.",
        viewerError: "Ups... pojawił się problem z oglądaniem lasu. Został on już zgłoszony odpowiednim specjalistom. Przepraszamy za niedogodności. Często wystarczy zamknąć okno przeglądarki i spróbować ponownie.",
        notEnoughQuiz: "Nie zmuszamy cię do zrobienia całego quizu, ale może chociaż połowę?",
        quizAllGood: "Wow! Już świetnie idzie Ci zmniejszanie Twego udziału w emisji dwutlenku węgla. Jeżeli nadal chcesz zasadzić wirtualne drzewko, po prostu zmień jedną ze swych odpowiedzi i  potraktuj jedną z rzeczy, które już robisz jako kredyt. Możesz też przejść na stronę główną aby obejrzeć drzewa innych.",
        noReminders: "Wiemy, że niełatwo zmienić swe przyzwyczajenia, ale docenimy, jeśli zdecydujesz  się wybrać chociaż jedno zobowiązanie, zanim pozwolimy ci zasadzić swoje drzewko.",
        mailError: "Ups... nie udało się nam wysłać do Ciebie maila! Przepraszamy!"
    }
};

function text(key) {
    return g_text[g_language][key] || g_text["en"][key] || "?";
}

// Utilities

function deferOnLoad(func) {
    document.observe('dom:loaded', function() { func.defer(); });
}

function getElementStyle(elt, ieStyleProp, cssStyleProp) {
    elt = $(elt);
    if (elt.currentStyle) {
        return elt.currentStyle[ieStyleProp];
    }
    else if (window.getComputedStyle) {
        return window.getComputedStyle(elt, "").getPropertyValue(cssStyleProp);
    }
    return "";
}

function assetUrl(name) {
    if (g_language == "en")
        return "/Content/" + name;
    else
        return "/Content/" + g_language + "/" + name;
}

// Avoid "click to install"

function writeObjectTags() {
    $$('script[type="x-object"]').each(function (elt) {
        elt.replace(elt.text);
    });
}

// Silverlight install experience

function setUpSLInstall() {
    if (Silverlight.isInstalled(g_slVersion)) {
        writeObjectTags();
    }
    else {
        $('get_sl_overlay').show();
        new ImageButton('sl_download_img', assetUrl("download_btn.png"), assetUrl("download_btn_hvr.png"));
        var timer = window.setInterval(function () {
            if (Silverlight.isInstalled(g_slVersion)) {
                window.clearInterval(timer);
                writeObjectTags();
                $('get_sl_overlay').hide();
            }
        }, 1000);
    }
}

function getBrowserInfo() {
    var str = "User-Agent: " + navigator.userAgent + "\n";
    return str;
}

var g_shownErrorAlready;

function onErrorHandler(sender, errorArgs)
{
    // The error message to display.
    var errorMsg = "Silverlight Error: \n\n";
    
    errorMsg += getBrowserInfo() + "\n";
    
    errorMsg += "URL: " + document.location + "\n\n";
    
    // Error information common to all errors.
    errorMsg += "Error Type:    " + errorArgs.errorType + "\n";
    errorMsg += "Error Message: " + errorArgs.errorMessage + "\n";
    errorMsg += "Error Code:    " + errorArgs.errorCode + "\n";
    
    // Determine the type of error and add specific error information.
    switch(errorArgs.errorType)
    {
        case "RuntimeError":
            // Display properties specific to RuntimeErrorEventArgs.
            if (errorArgs.lineNumber != 0)
            {
                errorMsg += "Line: " + errorArgs.lineNumber + "\n";
                errorMsg += "Position: " +  errorArgs.charPosition + "\n";
            }
            errorMsg += "MethodName: " + errorArgs.methodName + "\n";
            break;
        case "ParserError":
            // Display properties specific to ParserErrorEventArgs.
            errorMsg += "Xaml File:      " + errorArgs.xamlFile      + "\n";
            errorMsg += "Xml Element:    " + errorArgs.xmlElement    + "\n";
            errorMsg += "Xml Attribute:  " + errorArgs.xmlAttribute  + "\n";
            errorMsg += "Line:           " + errorArgs.lineNumber    + "\n";
            errorMsg += "Position:       " + errorArgs.charPosition  + "\n";
            break;
        default:
            break;
    }
    
    // Display the error message.
    if (window.console)
        console.log(errorMsg);
    
    var errorText = "viewerError";
    if (errorArgs.errorType == "ParserError" && errorArgs.lineNumber == 1 && errorArgs.charPosition == 3)
        errorText ="parserError";
    ReportError(errorText, errorMsg);
}

function ReportError(errorText, errorMsg) {
    new Ajax.Request("/ReportError", {
        method: "POST",
        parameters: {message: errorMsg}
    });
    
    if (!g_shownErrorAlready) {
        g_shownErrorAlready = true;
        alert(text(errorText));
    }
}

// Effect.Scroll

Effect.Scroll = Class.create();
Object.extend(Object.extend(Effect.Scroll.prototype, Effect.Base.prototype), {
  initialize: function(element) {
    this.element = $(element);
    if(!this.element) throw(Effect._elementDoesNotExistError);
    var options = Object.extend({
      x:    0,
      y:    0,
      mode: 'relative'
    }, arguments[1] || {});
    this.start(options);
  },
  
  setup: function() {
    this.element.makePositioned();
    this.originalLeft = parseFloat(this.element.scrollLeft || '0');
    this.originalTop  = parseFloat(this.element.scrollTop  || '0');
    if(this.options.mode == 'absolute') {
      // absolute movement, so we need to calc deltaX and deltaY
      this.options.x = this.options.x - this.originalLeft;
      this.options.y = this.options.y - this.originalTop;
    }
  },
  
  update: function(position) {
    this.element.scrollLeft = Math.round(this.options.x * position + this.originalLeft);
    this.element.scrollTop = Math.round(this.options.y * position + this.originalTop);
  }
});

// ImageButton

ImageButton = Class.create();
Object.extend(ImageButton.prototype, {
    initialize: function (element, upSrc, hoverSrc, disabledSrc) {
        if (disabledSrc === undefined)
            disabledSrc = upSrc;
        this.element = $(element);
        this.upSrc = upSrc;
        this.hoverSrc = hoverSrc;
        this.disabledSrc = disabledSrc;
        this.enabled = true;
        
        this.element.src = upSrc;
        new Image().src = hoverSrc;
        new Image().src = disabledSrc;
        
        this.element.style.cursor = "pointer";
        
        Event.observe(element, "mouseout", this.onMouseOut.bind(this));
        Event.observe(element, "mouseover", this.onMouseOver.bind(this));
        Event.observe(element, "click", this.handleClick.bind(this));
    },
    
    onMouseOut: function (event) {
        if (this.enabled)
            this.element.src = this.upSrc;
    },
    
    onMouseOver: function (event) {
        if (this.enabled)
            this.element.src = this.hoverSrc;
    },
    
    handleClick: function (event) {
        if (this.enabled && this.onClick)
            this.onClick(event);
    },
    
    setEnabled: function (state) {
        this.enabled = state;
        this.element.src = state ? this.upSrc : this.disabledSrc;
    }
});

// ImageSlideshow

ImageSlideshow = Class.create({
    initialize: function (element, pauseTime, srcList) {
        this.element = $(element);
        this.srcList = srcList;
        this.pauseTime = pauseTime;
        this.curImg = new Element("img", {alt: "", title: "", src: this.srcList[0]});
        this.nextImg = new Element("img", {alt: "", title: "", src: this.srcList[0]});
        this.nextImg.setOpacity(0);
        this.element.insert(this.curImg);
        this.element.insert(this.nextImg);
        this.iSrc = 0;
        srcList.each(function (src) { new Image().src = src; });
        this.pause();
    },
    
    pause: function () {
        this.curImg.src = this.srcList[this.iSrc];
        this.nextImg.setOpacity(0);
        window.setTimeout(this.nextSlide.bind(this), this.pauseTime);
    },
    
    nextSlide: function () {
        this.iSrc = (this.iSrc + 1) % this.srcList.length;
        this.nextImg.src = this.srcList[this.iSrc];
        new Effect.Opacity(this.nextImg, {duration: 1, from: 0, to: 0.99,
            afterFinish: this.pause.bind(this)});
    }
});

// HoverOutlineButton

HoverOutlineButton = Class.create({
    initialize: function (element, mainSrc, hoverSrc, offsetX, offsetY, altText) {
        this.element = $(element);
        
        this.element.makePositioned();
        
        this.element.insert("<img style='display: none; position: absolute; left: " + offsetX + "px; top: " + offsetY + "px;' src='" + hoverSrc + "' />");
        this.outline = this.element.down("img");
        if (mainSrc)
            this.element.insert({top: "<img style='display: block; position: absolute;' src='" + mainSrc + "' alt='" + altText + "' title='' />"});
        
        this.element.style.cursor = "pointer";
        
        this.element.observe("mouseover", this.onMouseOver.bindAsEventListener(this));
        this.element.observe("mouseout", this.onMouseOut.bindAsEventListener(this));
        this.element.observe("click", this.handleClick.bindAsEventListener(this));
        return this;
    },
    
    onMouseOver: function (event) {
        this.outline.show();
    },
    
    onMouseOut: function (event) {
        this.outline.hide();
    },
    
    handleClick: function (event) {
        if (this.onClick)
            this.onClick(event);
    }
});

// PromptingField

PromptingField = Class.create();
Object.extend(PromptingField.prototype, {
    // element should be an INPUT
    initialize: function (element, prompt) {
        this.element = $(element);
        this.element.promptingField = this;
        this.element.addClassName('prompting_field');
        new Insertion.Before(this.element, "<div class='field_prompt' style='display: none'>" + prompt + "</div>");
        this.label = $(this.element.previousSibling);
        if (this.element.id)
            this.label.id = this.element.id + "_prompt";
        this.label.style.fontSize = getElementStyle(this.element, "fontSize", "font-size");
        Event.observe(this.label, "click", this.onLabelClick.bindAsEventListener(this));
        Event.observe(this.element, "focus", Function.prototype.defer.bind(this.hidePrompt.bind(this)));
        Event.observe(this.element, "blur", Function.prototype.defer.bind(this.showPrompt.bind(this)));
        this.showPrompt();
    },
    
    onLabelClick: function (event) {
        this.element.focus();
    },
    
    hidePrompt: function (event) {
        this.label.hide();
    },
    
    showPrompt: function (event) {
        if (this.element.value == "")
            this.label.show();
    }
});

function makePromptingFields() {
    for (var i = 0; i < arguments.length; i += 2) {
        if ($(arguments[i]))
            new PromptingField(arguments[i], arguments[i+1]);
    }
}

// Cookie

var Cookie = {
  set: function(name, value, daysToExpire) {
    var expire = '';
    if (daysToExpire != undefined) {
      var d = new Date();
      d.setTime(d.getTime() + (86400000 * parseFloat(daysToExpire)));
      expire = '; expires=' + d.toGMTString();
    }
    return (document.cookie = escape(name) + '=' + escape(value || '') + expire + "; path=/");
  },
  
  get: function(name) {
    var cookie = document.cookie.match(new RegExp('(^|;)\\s*' + escape(name) + '=([^;\\s]*)'));
    return (cookie ? unescape(cookie[2]) : null);
  },
  
  erase: function(name) {
    var cookie = Cookie.get(name) || true;
    Cookie.set(name, '', -1);
    return cookie;
  },
  
  accept: function() {
    if (typeof navigator.cookieEnabled == 'boolean') {
      return navigator.cookieEnabled;
    }
    Cookie.set('_test', '1');
    return (Cookie.erase('_test') === '1');
  }
};

// Shared

function setupLangPicker() {
    if (g_language)
        $A($('lang_picker').options).each(function (o) { if (o.value == g_language) o.selected = true; });
    $('lang_picker').observe('change', function () {
        Cookie.set("lang", this.options[this.selectedIndex].value, 10000);
        document.location = document.location;
    });
}

// Trees/new

var curPage = 0;

function setupHistory() {
    SWFAddress.addEventListener(SWFAddressEvent.CHANGE, pageChange);
}

function pageChange(event) {
    curPage = event.value == "/" ? 0 : parseInt(event.value.substr(1));
    if (curPage == 3)
        chooseForest(parseInt($('forestId_field').value));
    scrollToPage(curPage);
}

function nextPageUnit(onFinish) {
    curPage++;
    SWFAddress.setValue("/" + curPage);
    scrollToPage(curPage, onFinish);
}

function scrollToPage(page, onFinish) {
    showAllPages();
    new Effect.Move('wall', {mode: 'absolute', x: -page * g_pageWidth,
                             afterFinish: function () {
                                hideOtherPages();
                                if (onFinish) onFinish(); }});
}

function showAllPages() {
    $$('.page_unit').each(function (page) { page.style.visibility = "visible"; });
}

function hideOtherPages() {
    $$('.page_unit').each(function (page, index) {
        page.style.visibility = (index == curPage) ? "visible" : "hidden";
    });
}

function submitPage1() {
    var numChecked = $$("#quiz input").inject(0, function (acc, btn) {
        return btn.checked ? acc+1 : acc;
    });
    
    if (numChecked < 5) {
        alert(text("notEnoughQuiz"));
        return;
    }
    
    if ($$("#quiz input").all(function (btn) { return (btn.value == "good" ? btn.checked : !btn.checked); })) {
        alert(text("quizAllGood"));
        return;
    }
    
    $$("#quiz input").each(function (btn) {
        if (btn.checked) {
            var itemId = btn.name.substr(1);
            var quizLine = $("r" + itemId + "_li");
            var quizBox = $("r" + itemId);
            if (btn.value == "bad") {
                quizLine.show();
                quizBox.checked = true;
            }
            else {
                quizLine.hide();
                quizBox.checked = false;
            }
        }
    });
    
    nextPageUnit();
}

var waitingForTree = false;

function submitPage2() {
    if (waitingForTree)
        return;
    
    $('err_name_taken').hide();
    $('err_no_email').hide();
    $('err_bad_email').hide();
    $('err_no_name').hide();
    
    if ($$("#reminders input").all(function (btn) { return !btn.checked; })) {
        alert(text("noReminders"));
        return;
    }
    
    var email = $('reminder_email').value.strip();
    if (email.length == 0) {
        $('err_no_email').show();
        return;
    }
    else if (!/^([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})$/i.test(email)) {
        $('err_bad_email').show();
        return;
    }
    
    var name = $('tree_name').value.strip();
    if (name.length == 0) {
        $('err_no_name').show();
        return;
    }
    
    waitingForTree = true;
    new Ajax.Request("/Trees/find?name=" + escape(name) + "&r=" + (new Date().valueOf()), {
        method: "GET",
        onSuccess: function (response) {
            waitingForTree = false;
            var result = response.responseJSON;
            if (result == null) {
                nextPageUnit(flyInHanky.curry("plantinforest_hanky", {parent: 'choose_forest'}));
            }
            else {
                $('err_name_taken').show();
            }
        },
        onFailure: function (response) {
            waitingForTree = false;
        }
    });
}

// Workaround for lack of inline-block in FF
function fixLabelsInFF() {
    var labels = $$('label[class="reminder_label"]');
    if (window.getComputedStyle && window.getComputedStyle(labels[0], null).display != "inline-block") {
        labels.each(function (label) {
            var labelContent = label.innerHTML;
            var labelWidth = document.defaultView.getComputedStyle(label, null).getPropertyValue('width');
            var labelSpan = document.createElement('span');
            labelSpan.style.display = 'block';
            labelSpan.style.width = labelWidth;
            labelSpan.innerHTML = labelContent;
            label.style.display = '-moz-inline-box';
            label.innerHTML = null;
            label.appendChild(labelSpan);
        });
    }
}

// Hanky

function flyInHanky(name, options) {
    if (!options)
        options = {};
    var id = "hanky_" + name;
    if ($(id))
        return;
    var img = new Element("img", {alt: "", title: "", style: "position: absolute; left: " + (options.from || 1100) + "px; z-index: 99"});
    if (options.url) {
        var link = new Element("a", {href: options.url});
        link.insert(img);
        link.id = id;
        $(options.parent || 'page_content').insert(link);
    }
    else {
        img.id = id;
        $(options.parent || 'page_content').insert(img);
    }
    img.observe("load", function () { new Effect.Move(img, {x: options.to || 614, mode: 'absolute'}); });
    img.src = assetUrl(name + ".png");
}

// Trees/new

function chooseForest(id) {
    $$('.species_list').each(function (elt) {
        if (elt.id == "species_list_" + id)
            elt.show();
        else
            elt.hide();
    });
    
    $('forestId_field').value = id;
}

function forestClick(id) {
    chooseForest(id);
    nextPageUnit();
}

function chooseSpecies(id) {
    $('speciesId_field').value = id;
    $('ownerEmail_field').value = $('reminder_email').value;
    $('name_field').value = $('tree_name').value;
    $('quizResult_field').value =
        $$('#reminders input').collect(function (box) {
            return box.checked ? box.id.substr(1) : "";
        }).join("");
    $('plant_form').submit();
}

// Forest/show

var pageParams = {};

function parseShowUrl() {
    var hashPos = document.URL.lastIndexOf("#");
    if (hashPos == -1)
        return;
    var fragment = document.URL.substr(hashPos + 1);
    pageParams = fragment.toQueryParams();
}

function searchForTree(event) {
    $('no_tree_result').hide();
    var name = $('search_box').value.strip();
    if (name.length == 0)
        return;
    waitingForTree = true;
    new Ajax.Request("/Trees/find?name=" + escape(name) + "&r=" + (new Date().valueOf()), {
        method: "GET",
        onSuccess: function (response) {
            waitingForTree = false;
            var info = response.responseJSON;
            if (info == null) {
                $('no_tree_result').show();
            }
            else {
                $('search_box').value = "";
                if (info.forestId == forestId) {
                    // TODO: hook up to history
                    $('SilverlightControl').Content.Explorer.Go(info.x, info.y - 110, info.id, -1);
                }
                else {
                    document.location = "/Trees/" + info.id;
                }
            }
        },
        onFailure: function (response) {
            waitingForTree = false;
        }
    });
    // TODO: progress indicator
}

function setUpSendForm() {
    new ImageButton('send_btn', assetUrl("send_btn.png"), assetUrl("send_btn_hvr.png")).onClick = sendView;
}

var sendValidateTimer;

function toggleSendForm() {
    if ($('send_slider').visible()) {
        new Effect.SlideUp('send_slider', {duration: 0.5});
        window.clearInterval(sendValidateTimer);
    }
    else {
        new Effect.SlideDown('send_slider', {duration: 0.5});
        sendValidateTimer = window.setInterval(validateSendForm, 200);
    }
}

function validateSendForm() {
    var ok = true;
    
    var to_email = $('send_to').value.strip();
    if (to_email.length == 0)
        ok =  false;
    if (!/^([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})$/i.test(to_email))
        ok =  false;
    
    var from_email = $('send_from').value.strip();
    if (from_email.length == 0)
        ok =  false;
    else if (!/^([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})$/i.test(from_email))
        ok =  false;
    
    if (ok)
        $('send_btn').show();
    else
        $('send_btn').hide();
}

var waitingForSend;

function sendView() {
    if (waitingForSend)
        return;
    waitingForSend = true;
    
    toggleSendForm();
    
    var explorer = $('SilverlightControl').Content.Explorer;
    var url = "/SendView?f=" + forestId + "&x=" + explorer.LocationX + "&y=" + explorer.LocationY +
        "&to=" + escape($('send_to').value) + "&from=" + escape($('send_from').value);
    new Ajax.Request(url, {
        method: "POST",
        onSuccess: function (response) {
            waitingForSend = false;
            new Effect.Appear('sent');
            new Effect.Fade('sent', {delay: 2.0});
        },
        onFailure: function (response) {
            waitingForSend = false;
            alert(text("mailError"));
        }
    });

}
