#include "common.h"

cMenu* gActiveMenu;
hash_obj* gMenu;
bool gMenuScrollCycle = true;

///////////////////////////////////////////////////////////////////////////////
// メニューモジュール初期化
///////////////////////////////////////////////////////////////////////////////
void cMenu::Init()
{
    gMenu = hash_new(10);
}

///////////////////////////////////////////////////////////////////////////////
// メニューモジュール終了処理
///////////////////////////////////////////////////////////////////////////////
void cMenu::Final()
{
    for(hash_it* i=gMenu->mEntryIt; i; i=i->mNextIt) {
        delete (cMenu*)i->mItem;
    }
    hash_delete(gMenu);
}

///////////////////////////////////////////////////////////////////////////////
// コンストラクタ
///////////////////////////////////////////////////////////////////////////////
cMenu::cMenu(char* title)
{
    strcpy(mTitle, title);

    mCursor = 0;
    mScrollTop = 0;

    mMenuItems = vector_new(10);
}

///////////////////////////////////////////////////////////////////////////////
// デストラクタ
///////////////////////////////////////////////////////////////////////////////
cMenu::~cMenu()
{
    for(int i=0; i<vector_size(mMenuItems); i++) {
        delete (sMenuItem*)vector_item(mMenuItems, i);
    }
    vector_delete(mMenuItems);
}

///////////////////////////////////////////////////////////////////////////////
// メニューに追加
///////////////////////////////////////////////////////////////////////////////
void cMenu::Append(char* name, int key, char* cmd)
{
    char buf[256];
    sprintf(buf, " %-40s", name);
    vector_add(mMenuItems, new sMenuItem(buf, key, cmd));
}

///////////////////////////////////////////////////////////////////////////////
// キー入力
///////////////////////////////////////////////////////////////////////////////
void cMenu::Input(int meta, int key)
{
    if(key == 1 || key == KEY_HOME) {        // CTRL-A
        mCursor = 0;
    }
    else if(key == 5 || key == KEY_END) {    // CTRL-E
        mCursor = vector_size(mMenuItems)-1;
    }
    else if(key == 14 || key == 6|| key == KEY_DOWN) {    // CTRL-N CTRL-F
        mCursor++;
    }
    else if(key == 16 || key == 2 || key == KEY_UP) {    // CTRL-P CTRL-B
        mCursor--;
    }
    else if(key == 4 || key == KEY_NPAGE) { // CTRL-D PAGE DOWN
        mCursor+=5;
    }
    else if(key == 21 || key == KEY_PPAGE) { // CTRL-U   PAGE UP
        mCursor-=5;
    }
    else if(key == 3 || key == 7 || key == 27) {    // CTRL-C CTRL-G Escape
        gActiveMenu = NULL;
        mclear();
    }
    else if(key == 10 || key == 13) {    // CTRL-M CTRL-J
        gActiveMenu = NULL;
        
        sMenuItem* item = (sMenuItem*)vector_item(mMenuItems, mCursor);
        
        mclear();
        view(true);
        mrefresh();
        
        int error;
        rb_eval_string_protect(item->mCmd, &error);
        
        output_eval_error(error);

        mclear();
    }
    else if(key == 12) {// CTRL-L
        mclear_immediately();
    }
    else {
        gActiveMenu = NULL;
        
        for(int i=0; i<vector_size(mMenuItems); i++) {
            sMenuItem* item = (sMenuItem*)vector_item(mMenuItems, i);
            
            if(item->mKey == key) {
                mclear();
                view(true);
                mrefresh();
                
                int error;
                rb_eval_string_protect(item->mCmd, &error);
                
                output_eval_error(error);
            }
        }
        
        mclear();
    }

    if(gMenuScrollCycle) {
        while(mCursor < 0) {
            mCursor += vector_size(mMenuItems);
        }
        while(vector_size(mMenuItems) != 0 && mCursor >= vector_size(mMenuItems)) {
            mCursor -= vector_size(mMenuItems);
        }
    }
    else {
        if(mCursor < 0) {
            mCursor = 0;
        }
        if(vector_size(mMenuItems) != 0 && mCursor >= vector_size(mMenuItems)) {
            mCursor = vector_size(mMenuItems)-1;
        }
    }

    const int maxy = mgetmaxy() -2;
    
    if(mCursor >= (mScrollTop+maxy)) {
        mScrollTop += mCursor - (mScrollTop+maxy) + 1;
    }
    if(mCursor < mScrollTop) {
        mScrollTop = mCursor;
    }
}

///////////////////////////////////////////////////////////////////////////////
// 描写
///////////////////////////////////////////////////////////////////////////////
void cMenu::View()
{
    const int maxx = mgetmaxx();
    const int maxy = mgetmaxy();

    int item_maxx = 0;
    for(int i=0; i<vector_size(mMenuItems); i++) {
        sMenuItem* item = (sMenuItem*)vector_item(mMenuItems, i);
        
        int len;
        if(gKanjiCode == kUtf8) {
            len = str_termlen(item->mName);
        }
        else {
            len = strlen(item->mName);
        }

        if(item_maxx < len) {
            item_maxx = len;
        }
    }
    item_maxx+=2;
    
    if(item_maxx < 43) {
        item_maxx = 43;
    }
    else if(item_maxx > maxx-2) {
        item_maxx = maxx-2;
    }
    
    const int size = vector_size(mMenuItems) + 2;
    mbox(0, 2, item_maxx, size < maxy ? size : maxy);

    mattron(kCABold);
    mmvprintw(0, 4, mTitle);
    mattroff();

    float f;
    if(vector_size(mMenuItems) == 0) {
        f = 0.0;
    }
    else {
        f = ((float)(mCursor+1)/(float)vector_size(mMenuItems))*100;
    }

    mmvprintw((size < maxy ? size: maxy) - 1, 2+item_maxx-8, "(%3d%%)", (int)f);

    for(int i=mScrollTop; (i<vector_size(mMenuItems) && i-mScrollTop<maxy-2); i++) {
        sMenuItem* item = (sMenuItem*)vector_item(mMenuItems, i);
        
        char buf[1024];
        if(strlen(item->mName) > maxx-4) {
            if(gKanjiCode == kUtf8)
                str_cut2(item->mName, maxx-4, buf, 1024);
            else
                cut(item->mName, buf, maxx-4);
        }
        else {
            strcpy(buf, item->mName);
        }
        
        if(i == mCursor) {
            mattron(kCAReverse);
            mmvprintw(i-mScrollTop+1, 3, buf);
            mattroff();
        }
        else  {
            mmvprintw(i-mScrollTop+1, 3, buf);
        }
    }

    mmove(maxy-1, maxx-2);
}

void cMenu::Show()
{
    mCursor = 0;
    mScrollTop = 0;
    
    View();
}
