/**
 * MixUp Arbitary Size Game
 * Serge Dolgov (C) 2002
 * studio.quazzle.com
 */

function QMixUpGame_show(show) {
    this.visible = show;
    if (this.loaded || !show) {
        for (var j=0; j<this.cells.length; j++) {
            var cell = this.cells[j];
            if (!this.cellX || (this.cellX != cell)) cell.show(show);
        }
    }
}

function QMixUpGame_update(compact) {
    for (var j=0; j<this.cells.length; j++) {
        var cell = this.cells[j];
        if (!this.cellX || (this.cellX != cell)) {
            cell.slideTo(this.lookupX(cell.index, compact),
                this.lookupY(cell.index, compact));
        }
    }
}

function QMixUpGame_cancel() {
    if (this._TID) {
        clearTimeout(this._TID);
        this._TID = null;
    }
}

function QMixUpGame_reset(compact) {
    this.cancel();
    for (var j=0; j<this.cells.length; j++) {
        var cell = this.cells[j];
        cell.index = cell.id = j;
        cell.slideTo(this.lookupX(j, compact), this.lookupY(j, compact));
    }
    this.cellX = null;
    this.ready = false;
    this.moves = 0;
    this.matched = 0;
}

function QMixUpGame_load() {
    this.cancel();
    if (this.cellX) this.reset(true);
    if (!this.loaded) {
        for (var j=0; j<this.cells.length; j++) this.cells[j].load(this.heap + j + this.heapext);
    }
    this.loaded = this.ready = this.over = false;
    this.busy = true;
    this.trackLoading(0);
}

function QMixUpGame_trackLoading(tick) {
    this._TID = null;
    if (tick < 300) {
        var count = 0;
        if (tick) {
            for (var j=0; j<this.cells.length; j++) count += this.cells[j].face.complete && 1;
            if (this.onLoading) this.onLoading(count);
        }
        if (count < this.cells.length) {
            this._TID = setTimeout(this.name + ".trackLoading(" + (++tick) + ")", 1000);
        } else {
            this.loaded = true;
            this.busy = false;
            if (this.visible) this.show(true);
            if (this.onLoad) this.onLoad();
        }
    } else {
        if (this.onError) this.onError("Internet connection lost.");
    }
}

function QMixUpGame_shuffle() {
    if (this.loaded) {
        this.cancel();
        this.ready = this.over = false;
        this.busy = true;
        if (!this.cellX) this.cellX = this.cells[Math.floor(Math.random() *
            (this.cells.length - .001))];
        this.cellX.show(false);
        this.update();
        this.trackShuffling(0);
    }
}

function QMixUpGame_trackShuffling(tick) {
    this._TID = null;
    if (!tick) {
        this._TID = setTimeout(this.name + ".trackShuffling(1)",
            this.visible ? 1500 : 20);
    } else if (tick > this.cells.length * 2) {
        this.ready = true;
        this.busy = false;
        this.matched = 0;
        for (var j=0; j<this.cells.length; j++) {
            var cell = this.cells[j];
            this.matched += (cell.index == cell.id) && 1;
        }
        if (this.onReady) this.onReady();
    } else {
        var i = null;
        var j = null;
        var mult = this.cells.length - .001;
        while ((i == j) || (this.cellX == i) || (this.cellX == j)) {
            i = this.cells[Math.floor(Math.random() * mult)];
            j = this.cells[Math.floor(Math.random() * mult)];
        }
        var k = j.index;
        j.index = i.index;
        i.index = k;
        i.slideTo(this.lookupX(i.index), this.lookupY(i.index));
        j.slideTo(this.lookupX(j.index), this.lookupY(j.index));
        this._TID = setTimeout(this.name + ".trackShuffling(" + (++tick) + ")",
            this.visible ? 150 : 20);
    }
}

function QMixUpGame_handleClick(tag) {
    with (this.parent) {
        if (loaded && ready && !over) {
            var i = Math.floor(this.index % this.hsize);
            var j = Math.floor(this.index / this.hsize);
            if (((i < 1) || (this.index - 1 != cellX.index)) &&
                ((i >= hsize - 1) || (this.index + 1 != cellX.index)) &&
                ((j < 1) || (this.index - hsize != cellX.index)) &&
                ((j >= vsize - 1) || (this.index + hsize != cellX.index))) {
                this.shake();
            } else {
                this.parent.moves++;
                i = cellX.index;
                cellX.index = this.index;
                this.index = i;
                if (i == this.id) this.parent.matched++;
                if (cellX.index == this.id) this.parent.matched--;
                this.slideTo(lookupX(i), lookupY(i));
                if (this.parent.onScore) onScore(moves, matched);
                if (matched >= cells.length) {
                    this.parent.over = true;
                    cellX.show(true);
                    update(true);
                    raiseGameOver(0);
                }
            }
        } else {
            this.shake();
        }
    }
}

function QMixUpGame_raiseGameOver(tick) {
    if (tick) {
        if (this.onGameOver) this.onGameOver(this.moves, this.matched);
    } else {
        setTimeout(this.name + ".raiseGameOver(1)", 2000);
    }
}

function QMixUpGame_lookupX(index, compact) {
    with (this) {
        return compact
            ? poscx + Math.floor(index % hsize) * cellwidth
            : posx + Math.floor(index % hsize) * (cellwidth + padding);
    }
}

function QMixUpGame_lookupY(index, compact) {
    with (this) {
        return compact
            ? poscy + Math.floor(index / hsize) * cellheight
            : posy + Math.floor(index / hsize) * (cellheight + padding);
    }
}

function QMixUpGame(parent, name, posx, posy, hsize, vsize, cellwidth, cellheight, padding, fileheap, ext) {
    this.init(parent, name);
    this.posx = posx || 0;
    this.posy = posy || 0;
    this.hsize = hsize || 4;
    this.vsize = vsize || 4;
    this.cellwidth = cellwidth;
    this.cellheight = cellheight;
    this.padding = padding || 6;
    this.heap = fileheap || "/";
    this.heapext = ext || ".gif";
    this.poscx = this.posx + Math.floor((this.hsize - 1) * this.padding / 2);
    this.poscy = this.posy + Math.floor((this.vsize - 1) * this.padding / 2);
    this.cells = new Array(this.hsize * this.vsize);
    this.cellX = null;    // empty cell
    this.busy = this.loaded = this.ready = this.over = false;
    this.visible = false;
    this.moves = 0;
    this.matched = 0;
    this.show = QMixUpGame_show;
    this.update = QMixUpGame_update;
    this.cancel = QMixUpGame_cancel;
    this.reset = QMixUpGame_reset;
    this.lookupX = QMixUpGame_lookupX;
    this.lookupY = QMixUpGame_lookupY;
    this.handleClick = QMixUpGame_handleClick;
    this.load = QMixUpGame_load;
    this.trackLoading = QMixUpGame_trackLoading;
    this.shuffle = QMixUpGame_shuffle;
    this.trackShuffling = QMixUpGame_trackShuffling;
    this.raiseGameOver = QMixUpGame_raiseGameOver;
    if (this.cells.length > 1) {
        var k;
        for (var j=0, k=0; j<this.vsize; j++) {
            for (var i=0; i<this.hsize; i++, k++) {
                var cell = new QMixUpCell(this, "cells[" + k + "]", cellwidth, cellheight,
                    this.lookupX(k, true), this.lookupY(k, true), this.heap + "_.gif", true);
                cell.index = cell.id = k;
                cell.onClick = this.handleClick;
                this.cells[k] = cell;
            }
        }
    } else {
        write('Invalid game parameters');
    }
}
QMixUpGame.prototype = new QControl();