Ext.BLANK_IMAGE_URL = '../js/ext/resources/images/default/s.gif';
Ext.QuickTips.init();

// オンメモリ DB
todoPs = {
    data:	[],
    // 新規レコードを取得
    getNew: function() {
        var me = todoPs;
        var d = new Date();
        var rec = {
            created:	'' + d + ':' + d.getMilliseconds(),
            todo:	'** 新規 ToDo **',
            finished:	0
        };

        me.data.push(rec);  // 末尾へ追加
        me.save();
        return rec;
    },
    // 全レコードの配列を取得
    getAll: function() {
        var all = [];

        Ext.each(this.data, function(item) {
            all.push([item.created, item.todo, item.finished]);
        }, this);

        return all;
    },
    // レコードを更新
    update: function(rc) {
        var me = todoPs;

        Ext.each(me.data, function(item, pos, data) {
            if (item.created == rc.created) {
                me.data[pos] = rc;
            }
        }, this);
        me.sync();
    },
    // レコードを削除 (保存はしない)
    delRec: function(rc) {
        var me = todoPs;

        // alert(rc.created);

        Ext.each(me.data, function(item, pos, data) {
            if (item.created == rc.created) {
                delete me.data[pos];
            }
        }, this);
    },
    // 1 レコードを削除して保存する。
    delRecOne: function(rc) {
        var me = todoPs;

        me.delRec(rc);
        me.sync();
    },
    // 複数行を削除
    delRecSet: function(rcs) {
        var me = todoPs;

        Ext.each(rcs, function(item) {
            if (item.created == rc.created) {
                me.delRec(item)
            }
        }, this);
        me.sync();
    },

    // ローカルストレージへ保存
    save: function() {
        localStorage.todoPs = Ext.encode(this.data);
    },
    // ローカルストレージを展開
    load: function() {
        var data = localStorage.todoPs;

        if (data != null) {
            this.data = Ext.decode(data);
        }
        if (this.data == null) {
            this.data = [];
        }
    },
    sync: function(data) {
        this.save();
        this.load();
    },
    setData: function(storeData) {
        this.data =[];
        for (i = 0; i < storeData.length; i++) {
            var rec = {
                created:  storeData.items[i].data.created,
                todo:     storeData.items[i].data.todo,
                finished: storeData.items[i].data.finished
            };
            this.data[i] = rec;
        }
        this.sync();
    }
};

// Ext.ux.GridDDTextに渡す、ddText加工用の関数
var ddfn = function(grid, sel){
    var rows = [];
    rows.push('行の移動はドラッグ＆ドロップで行えます。');

    rows.push('<div class="drag-box">');
    
    for(var i = 0; i < sel.length; i++) {
        rows.push('<div class="drag-box-row">');
        rows.push(sel[i].data['todo']);
        rows.push('</div>');
    }

    rows.push('</div>');

    // console.log(rows.join(''));
    return rows.join('');
};

// アプリケーション
var app = {
    // 初期化
    init: function() {
        todoPs.load();
    },
    // 表示
    show: function() {
        grid = this._todoPanel();
        new Ext.Viewport({
            layout:	'border',
            defaults:	{
                layout:	'fit',
                border:	false
            },
            items:	[{
                region:		'center',
                items:		[grid]
            }, {
                region:		'south',
                contentEl:	'attention'
            }]
        });
    },
    // ストア初期化
    _initStore: function() {
        var st = new Ext.data.ArrayStore({
            fields:	['created', 'todo', 'finished'],
            data:	todoPs.getAll(),
            listeners: {
                update: function(st, rc) {
                    if (rc.dirty) {
                        todoPs.update(rc.data);
                        rc.commit();
                    }
                    return true;
                }
            }
        });

        return st;
    },

    // setData の処理
    setData:  function(storeData) {
        todoPs.setData(storeData);
    },
    // パネル初期化
    _todoPanel: function() {
        var me = this;

        var myStore = this._initStore();

        // 追加の処理
        var append = function() {
            var rec = todoPs.getNew();
            myStore.add(new myStore.recordType(rec));
        };
        // 削除の処理
        var remove = function(rec) {
            todoPs.delRecOne(rec.data);
            myStore.remove(rec);
        };
        // 選択行削除の処理
        var remove_selected = function() {
            var list = grid.selModel.getSelections();
            if (list.length == 0) {
                Ext.Msg.show({
                    title:'Info',
                    msg: '選択行がありません。<br/>マウス右クリックで行を削除することもできます。',
                    buttons: Ext.Msg.OK,
                    icon: Ext.Msg.INFO
                });
            }
            Ext.each(list, function(item) {
                remove(item);
            }, this);
        };

        // フィルターの処理
        var filter = function(bt) {
            if (bt.id == 'fl_2') {
                myStore.clearFilter();
            } else {
                myStore.filterBy(function(rc) {
                    return rc.get('finished') == bt.id[3];
                }, this);
            }
        };

        // 完了ステータス用チェックカラム
        var finishedColumn = new Ext.grid.CheckColumn({
            header:	'完了',
            dataIndex:	'finished',
            sortable:   false,
            width:	60
        });

        // 複数選択可能とする。
        var sm = new Ext.grid.RowSelectionModel({
            singleSelect: false
        });

        // ColumnModelオブジェクトの生成
        var cm = new Ext.grid.ColumnModel({
            defaults: {  
                sortable: false
            },
            columns: [
            // new Ext.grid.RowNumberer(),
            finishedColumn,
            {
                id:         'todo',
                header:     'ToDo',
                dataIndex:  'todo',
                editor: {
                    xtype:  'textfield'
                }
            }
            ]
        });

        var contextMenu = new Ext.menu.Menu({
            items: [
            {
                text:       '削除',
                iconCls:    'delete',
                scope:      this,
                handler:    function(btn){
                    var record = grid.selModel.getSelected();
                    // Ext.Msg.alert('選択中の行の削除', '「' + record.get('todo') + '」を削除しますか？');
                    remove(record);
                }
            }
            ]
        });
            
        // パネル作成
        grid = new Ext.grid.EditorGridPanel({
            title:          'Simple ToDo',
            store:          myStore,
            plugins:        [finishedColumn],
            cm:             cm,         // ColumnModel の設定
            sm:             sm,         // SelectionModel の設定

            plugins: [new Ext.ux.GridDDText(ddfn)], // ddTextの内容を変更するためのプラグイン
            enableDragDrop: true,       // ドラッグ＆ドロップ可能に
            ddGroup:        'GridDD',   // ドラッグ＆ドロップグループ
            //ddText:         '行の移動はドラッグ＆ドロップで行えます',    // 行を選択時にでるメッセージ

            autoExpandColumn:   'todo',
            border:             false,
            stripeRows:         true,
            tbar:	[
            {
                text:       '追加',
                iconCls:    'add',
                tooltip:    'テーブルの末尾に新規行を追加します。',
                handler:    append
            },
            {
                text:       '削除',
                iconCls:    'delete',
                tooltip:    '選択されている行を削除します。',
                handler:    remove_selected
            },
            '-',
            '   ',
            'フィルター： ',
            {
                id:     'fl_0',
                text:   '未完',
                tooltip: '未完のものを表示',
                handler: filter
            },
            '-',
            {
                id:     'fl_1',
                text:   '完了',
                tooltip: '完了したものを表示',
                handler:filter
            },
            '-',
            {
                id:     'fl_2',
                text:   'すべて',
                tooltip: 'すべてを 表示',
                handler:filter
            }
            ],
            //イベントを設定する。
            /**
             *  今回はどちらのイベントも引数は同じ。
             *  rowcontextmenu:ダブルクリックイベント
             *      grid: グリッド
             *      row: クリックした行のインデックス
             *      e: イベントオブジェクト
             */
            listeners:{
                rowcontextmenu:function(grid, row, e){
                    //右クリックでセレクト処理(セレクトしたものを後で右クリックメニューで取得する)
                    grid.getSelectionModel().selectRow(row);

                    //右クリックイベントを止める。ここで止めないとブラウザの右クリックメニューが表示されてしまう。
                    e.stopEvent();

                    //コンテクストメニューを表示
                    contextMenu.showAt(e.getXY());
                }
            }
        });

        return grid;
    }
};

Ext.onReady(function() {
    app.init();
    app.show();


    // ドラッグ＆ドロップ時の処理
    // TODO: target 位置の強調表示
    //       drag 表示にデータ内容・順番を表示する。
    
    var griddd = new Ext.dd.DropTarget(grid.container, {

        ddGroup: 'GridDD',

        notifyDrop: function(dd, e, data) {

            // ドロップされた行の id
            var toindex = dd.getDragData(e).rowIndex;
            var work = [];

            // selections には 選択した順番で積まれているので、その順番を活かす。
            // 選択された行を削除して、work[] に移動する。
            for (i = 0; i < data.selections.length; i++) {
                var rowData = grid.store.getById(data.selections[i].id);
                work.push(rowData);
                var sindex = data.grid.store.findExact('created', rowData.data.created);
                // ドロップされた行の index を補正する
                if (toindex >= 0) {
                    if (sindex < toindex) {
                        toindex = toindex -1;
                    }
                }
                data.grid.store.remove(grid.store.getById(data.selections[i].id));
            }
            if (toindex >= 0) {
                // 選択された行を順番を保って ドロップされた行の上に work[] を insert する
                data.grid.store.insert(toindex, work.reverse());
            } else {
                // 選択された行を末尾 順番を保って add する
                data.grid.store.add(work);
            }

            // 選択の解除
            grid.getSelectionModel().clearSelections();

            // localDB に反映させる。
            app.setData(grid.store.data);
         
            return true;
        }
    });
});
