//---- Settings -------------------------------------------------------------//

var maxWidth = 300;
var maxHeight = 200;

var fadeTime = 500;
var movementTime = 500;

var updateDelay = 2000;
var loopDelay = 200;

var refreshUrl = 'get_notes.php';
var submitUrl= 'submit.php';

//---- Core -----------------------------------------------------------------//

// these are set from the DOM
var width = 100;
var height = 100;

var desktopId = '';

var timeUntilRefreshRequest = 0;

var notes = {};

function getDesktop() {
    return $(desktopId);
}

function init(id) {
    desktopId = '#' + id;

    var desktop = getDesktop();
    width = desktop.width();
    height = desktop.height();
    desktop.empty();

    $('#add_note').click(function () {
        var x = Math.random() * (width - maxWidth);
        var y = Math.random() * (height - maxHeight);
        makeAdditionBox(x, y).find('.submit_text').focus();

        return false;
    });

    mainLoop();
}

function mainLoop() { 
    setTimeout(mainLoop, loopDelay);

    timeUntilRefreshRequest -= loopDelay;
    if(timeUntilRefreshRequest <= 0) {
        refreshRequest();
        timeUntilRefreshRequest = updateDelay;
    }
}

function forceRefreshRequest() {
    refreshRequest();
    timeUntilRefreshRequest = updateDelay;
}

//---- Note Class -----------------------------------------------------------//

function Note(id, x, y, type, content) {
    this.id = id;
    this.x = x;
    this.y = y;
    this.html = makeContentHTML(id, type, content);
}

Note.prototype.show = function () {
    var div = this.getDiv();

    // If the note doesn't have a div, make one.
    if(!div)
    {
        this.makeDiv();
        div = this.getDiv();
    }

    div.fadeIn(fadeTime);
}

Note.prototype.hide = function () {
    var div = this.getDiv();
    if(div) {
        div.fadeOut(fadeTime);
    }
}

Note.prototype.moveTo = function (x, y) {
    var div = this.getDiv();
    var pos = getTopLeftCoords(div, x, y);

    this.x = x;
    this.y = y;
    div.animate({left: pos.x, top: pos.y}, movementTime);
}

Note.prototype.die = function () {
    var div = this.getDiv();
    if(div) {
        div.fadeOut(fadeTime, function () {
            $(this).remove();
        });
    }
}

Note.prototype.getDivId = function () {
    return 'note_' + this.id;
}

Note.prototype.getDiv = function () {
    var ret = $('#' + this.getDivId());
    return ret.length > 0 && ret;
}

Note.prototype.makeDiv = function () {
    var div = makeBoxDiv();
    div.find('.content').append(this.html);
    var pos = getTopLeftCoords(div, this.x, this.y);
    div.attr('id', this.getDivId())
       .css('left', pos.x)
       .css('top', pos.y)
       .hide()
       .appendTo(getDesktop());

    var id = this.id;
    div.draggable({
        cancel: '.content, .delete',
        containment: getDesktop(),
        helper: 'clone',
        opacity: 0.5,
        stop: function (e, ui) {
            var desktopPos = getDesktop().offset();
            var pos = ui.helper.offset();
            var x = pos.left - desktopPos.left;
            var y = pos.top - desktopPos.top;
            movementRequest(id, x, y);
        }
    });

    div.find('.delete').click(function () {
        deleteRequest(id);
    });
}

function getTopLeftCoords(div, x, y) {
    var newX = Math.max(0, Math.min(x, width - div.outerWidth()));
    var newY = Math.max(0, Math.min(y, height - div.outerHeight()));
    return { x: newX, y: newY };
}

function makeContentHTML(id, type, content) {
    if(type == 'text') {
        return content;
    } else if(type == 'fixed') {
        return $('<pre/>').append(content);
    } else if (type == 'image') {
        var image = $('<img/>')
            .load(function () {
                var imageWidth = image.width();
                var imageHeight = image.height();

                var xscale = maxWidth / imageWidth;
                var yscale = maxHeight / imageHeight;
                var scale = Math.min(1, Math.min(xscale, yscale));
                image.width(scale * imageWidth)
                     .height(scale * imageHeight)
                     .show(fadeTime);
            })
            .attr('src', content)
            .hide();
        return image;
    } else {
        return '<strong>unknown content type</strong>'
    }
}

function makeBoxDiv() {
    var del = $('<img/>')
        .attr('src', 'images/close.png')
        .attr('alt', 'delete')
        .addClass('delete');
    var titlebar = $('<div/>')
        .addClass('titlebar')
        .append(del);

    var content = $('<div/>')
        .addClass('content');

    return $("<div/>")
        .addClass('note')
        .append(titlebar)
        .append(content);
}

//---- Addition UI ----------------------------------------------------------//

function makeOption(value, text) {
    return $('<option/>').attr('value', value).append(text);
}

function makeAdditionBox (x, y) {
    var text = $('<textarea/>')
        .addClass('submit_text')
        .attr('rows', '6');

    var type = $('<select/>')
        .addClass('submit_type')
        .attr('name', 'type')
        .append(makeOption('text', 'Text'))
        .append(makeOption('fixed', 'ASCII Art'))
        .append(makeOption('image', 'Image (URL)'));

    var submit = $('<input type=\'submit\' />')
        .addClass('submit_button')
        .attr('value', 'add');

    var form = $('<form/>')
        .attr('id', 'desktop_form')
        .attr('action', '')
        .append(text)
        .append(type)
        .append(submit);

    var div = makeBoxDiv()
        .css('left', x)
        .css('top', y)
        .hide();
    div.find('.content').append(form);
    div.find('.delete').click(function () {
        div.fadeOut(fadeTime, function () {
            div.remove();
        })
    });

    div.appendTo(getDesktop()).fadeIn(fadeTime);

    div.draggable({
        cancel: '.content, .delete',
        containment: getDesktop(),
    });

    submit.click(function () {
        var desktopPos = getDesktop().offset();
        var pos = div.offset();
        var x = pos.left - desktopPos.left;
        var y = pos.top - desktopPos.top;
        additionRequest(x, y, type.val(), text.val());
        div.fadeOut(fadeTime, function () {
            div.remove();
        });
        return false;
    });
    return div;
}

//---- Requests -------------------------------------------------------------//

var lastRefreshRequest = false;
var preventRefresh = false;

function additionRequest(x, y, type, content) {
    postRequest({ request: 'add', x: x, y: y, type: type, content: content });
}

function deleteRequest(id) {
    postRequest({ request: 'delete', id: id });
}

function movementRequest(id, x, y) {
    postRequest({ request: 'move', id: id, x: x, y: y });
}

function postRequest(data)
{
    preventRefresh = true;

    $.ajax({
        cache: false,
        complete: function () {
            preventRefresh = false;
            forceRefreshRequest();
        },
        data: data,
        type: 'post',
        url: submitUrl,
        //success: function (data) { alert(data); },
    });
}

function refreshRequest() {
    if(preventRefresh) return;

    var thisRequest = $.getJSON( refreshUrl, {}, function(data) {
        // If a new request was started before this was called we want to
        // ignore the old results.
        if (lastRefreshRequest === thisRequest && !preventRefresh) {
            setNewNotes(data.notes);
        }
    });
    lastRefreshRequest = thisRequest;
}

function setNewNotes(newNoteData) {
    var newNotes = {};

    // for each new note
    newNoteData.forEach(function (note) {
        if(notes[note.id]) {
            // move the old note if it exists
            if(notes[note.id].x != note.x ||
               notes[note.id].y != note.y) {
                notes[note.id].moveTo(note.x, note.y);
            }
            newNotes[note.id] = notes[note.id];
        } else {
            // otherwise create a new note
            newNotes[note.id] =
                new Note(note.id, note.x, note.y, note.type, note.content);
            newNotes[note.id].show();
        }
    });

    // kill off notes which are no longer around
    for(i in notes){
        if(!newNotes[notes[i].id]) {
            notes[i].die();
        }
    }

    // replace old note list with new note list
    notes = newNotes
}

