
// TODO: クラス定義の仕方を勉強して、書き直すこと。

/**
 * コンストラクタ.
 * @constructor
 * @param {Raphael} paper 描画先.
 * @param {String} name 名前.
 */
var Deck = function(paper, name) {
    this.paper = paper;
    this.name = name;
    this.backname = Deck.Backs[0];

    this.card = [];
    for (var s = 0; s < Deck.Suits.length; s++) {
        for (var r = 0; r < Deck.Ranks.length; r++) {
            var cardname = Deck.Suits[s] + Deck.Ranks[r];
            var id = Deck.name2id(cardname);
            this.card[id] = new Card(paper, this,
                cardname, r * 76, s * 100, turn);
        }
    }
    // JOKER
    this.card[52] = new Card(paper, this, Deck.Jokers[0], 0, 4 * 100, turn);
};

/**
 * カード名 -> カード番号に変換する.
 * @param {String} name カードの名前.
 * @return {int} カード番号.
 */
Deck.name2id = function(name) {
    if (name === Deck.Jokers[0]) {
        return 52;
    }
    var sName = name.charAt(0);
    var fName = name.charAt(1);
    var s = -1;
    var r = -1;
    var i;
    for (i = 0; i < Deck.Suits.length; i++) {
        if (sName === Deck.Suits[i]) {
            s = i;
            break;
        }
    }
    for (i = 0; i < Deck.Ranks.length; i++) {
        if (fName === Deck.Ranks[i]) {
            r = i;
            break;
        }
    }
    return s * 13 + r;
};
/** スーツ. */
Deck.Suits = ['C', 'D', 'H', 'S'];
/** ランク. */
Deck.Ranks = ['2', '3', '4', '5', '6', '7', '8', '9', 'T', 'J', 'Q', 'K', 'A'];
/** ランク. */
Deck.RankStr = '23456789TJQKA';

/** 黒いジョーカーの名前. */
Deck.Jokers = ['JB'];

/** 裏面の画像の名前. */
Deck.Backs = ['BB'];

/**
 * カード番号 -> カード名に変換する.
 * @param {int} id カードの番号.
 * @return {String} カードの名前.
 */
Deck.id2name = function(id) {
    if (id == 52) {
        return Deck.Jokers[0];
    }
    var s = id / 13;
    var r = id % 13;
    return Deck.Suits[s] + Deck.Ranks[r];
};

Deck.prototype = {
    constructor: Deck,
    getCardByName: function(name) {
        return this.card[Deck.name2id(name)];
    },
    getCardById: function(id) {
        return this.card[id];
    }
};

/**
 * コンストラクタ.
 * @constructor
 * @param {Raphael} paper 描画先.
 * @param {Deck} deck  カードのデック.
 * @param {String} name  デックの名前.
 * @param {int} x  x座標.
 * @param {int} y  y座標.
 * @param {function} func  カード反転のエフェクト.
 */
var Card = function(paper, deck, name, x, y, func) {
    this.paper = paper;
    this.deck = deck;
    this.init(name, x, y, func);
};

Card.prototype = {
    constructor: Card,

    init: function(name, x, y, turnEfect) {
        this.name = name;
        this.x = x;
        this.y = y;
        this.turnEfect = turnEfect;

        this.face = true;

        var paper = this.paper;
        var back_name = this.deck.backname;
        var card = this;
        var deck = this.deck;

        var img = new Image();
        img.src = 'images/' + name + '.png';

        img.onload = function() {
            card.width = img.width;
            card.height = img.height;
            card.cx = x + card.width / 2;
            card.cy = y + card.height / 2;

            var backImg = new Image();

            backImg.src = 'images/' + back_name + '.png';
            backImg.deck = this.deck;

            backImg.onload = function() {
                card.cback = paper.image(
                    backImg.src, 0, 0, backImg.width, backImg.height);
                card.cback.attr({
                    opacity: 0
                });

                card.cface = paper.image(
                    img.src, 0, 0, this.width, this.height);
                card.cface.name = name;
                card.cface.deck = deck;

                // card.cface.dblclick(turnFunc);
                // card.cface.click(turnFunc);
                card.cface.click(clickFunc);
                card.cface.drag(moveFunc, startFunc, endFunc);

                card.cface.translate(x, y);
                card.cback.translate(x, y);
            }
        };
        return this;

        function turnFunc(event) {
            var card = this.deck.getCardByName(this.name);
            if (card.face) {
                card.turnEfect(
                    card.cface, card.cback, card.cx, card.cy);
                card.face = false;
            } else {
                card.turnEfect(
                    card.cback, card.cface, card.cx, card.cy);
                card.face = true;
            }
        }
        function clickFunc(event) {
            var card = this.deck.getCardByName(this.name);
            alert('clicked ' + card.name);
        }
        function moveFunc(dx, dy, x, y) {
        }
        function startFunc() {
        }
        function endFunc() {
        }
    },
    moveTo: function(x, y) {
        var dx = x - this.x;
        var dy = y - this.y;
        this.move(dx, dy);
    },
    move: function(dx, dy) {
        this.x += dx;
        this.y += dy;
        this.cx = this.x + this.width / 2;
        this.cy = this.y + this.height / 2;

        this.cface.translate(dx, dy);
        this.cback.translate(dx, dy);
    },
    toFront: function() {
        this.cback.toFront();
        this.cface.toFront();
    },
    toBack: function() {
        this.cface.toBack();
        this.cface.toBack();
    }
};
