extern "C"
{
#include <stdio.h>
#include <curses.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <time.h>
#include <utime.h>
#include <unistd.h>
#include <signal.h>
#include "ruby.h"
}

void sig_exit(int signal)
{
    exit(1);
}

int main(int argc, char* argv[])
{
    /// is terminal ///
    if(!isatty(0) || !isatty(1)) {
        fprintf(stderr, "standard input is not a tty\n");
        return 1;
    }

    /// signal ///
    signal(SIGINT, sig_exit);
    signal(SIGQUIT, sig_exit);
    signal(SIGABRT, sig_exit);
    signal(SIGKILL, sig_exit);
    signal(SIGPIPE, sig_exit);
    signal(SIGALRM, sig_exit);
    signal(SIGTERM, sig_exit);
    signal(SIGHUP, sig_exit);

    /// check ///
    if(argc < 2) {
        fprintf(stderr, "no argument\n");
        exit(1);
    }
    for(int i=1; i<argc; i++) {
       if(access(argv[i], F_OK) != 0) {
           fprintf(stderr, "invalid file name\n");
           exit(1);
       }
    }
    
    /// editing mode ///
    enum eEditing { kReadOnly, kSystem, kHidden, kArchive, kOK };
    eEditing editing = kReadOnly;
    bool cancel = false;

    
    /// start ruby ///
    ruby_init();
    
    /// Windows Attribute ///
    enum eAttribute { kNoChange, kOff, kOn };
    
    eAttribute readonly = kNoChange;
    eAttribute hidden = kNoChange;
    eAttribute asystem = kNoChange;
    eAttribute archive = kNoChange;
    
    if(argc == 2) {
        char cmd[1024];
        sprintf(cmd, "output = `attrib '%s'`; s = output.split; if s[s.size-2] == \"-\" then nil else result = []; result[0] = (output[0]==32)?false:true; result[1] = (output[3]==32)?false:true; result[2]=(output[4]==32)?false:true; result[3]=(output[5]==32)?false:true; result end", argv[1]);
        VALUE attrib = rb_eval_string(cmd);
        
        if(attrib != Qnil) {
            if(rb_ary_entry(attrib, 3) == Qtrue) {  // readonly
                readonly = kOn;
            }
            else {
                readonly = kOff;
            }
            if(rb_ary_entry(attrib, 2) == Qtrue) {  // hidden
                hidden = kOn;
            }
            else {
                hidden = kOff;
            }
            if(rb_ary_entry(attrib, 1) == Qtrue) {  // asystem
                asystem = kOn;
            }
            else {
                asystem = kOff;
            }
            if(rb_ary_entry(attrib, 0) == Qtrue) {  // archive
                archive = kOn;
            }
            else {
                archive = kOff;
            }
        }
    }
    
    /// start curses ///
    initscr();
    noecho();
    keypad(stdscr, 1);
    raw();

    clear();

    /// start main loop ///
    
    int key = -1;
    while(1) {
        /// draw ///
        attron(A_REVERSE);
        mvprintw(0,0, "+++ mattrcyg (attribute editor) +++");
        attroff(A_REVERSE);

        mvprintw(2, 0, "OK -> Enter Key, Cansel -> CTRL+C");

        mvprintw(4,0, "readonly  : ");
        
        if(readonly == kNoChange) {
            printw("NO CHANGE");
        }
        else if(readonly == kOn) {
            printw("On       ");
        }
        else {
            printw("Off      ");
        }
        
        mvprintw(5,0, "hidden    : ");
        if(hidden == kNoChange) {
            printw("NO CHANGE");
        }
        else if(hidden == kOn) {
            printw("On       ");
        }
        else {
            printw("Off      ");
        }
        
        mvprintw(6,0, "system    : ");
        if(asystem == kNoChange) {
            printw("NO CHANGE");
        }
        else if(asystem == kOn) {
            printw("On       ");
        }
        else {
            printw("Off      ");
        }
        
        mvprintw(7,0, "archive   : ");
        if(archive == kNoChange) {
            printw("NO CHANGE");
        }
        else if(archive == kOn) {
            printw("On       ");
        }
        else {
            printw("Off      ");
        }
        
        if(editing == kOK)
            mvprintw(9, 0, "Write OK?(Y/n)");        

        /// cursor ///
        switch(editing) {
        case kReadOnly:
            move(4, 12);
            break;
            
        case kHidden:
            move(5, 12);
            break;
            
        case kSystem:
            move(6, 12);
            break;
            
        case kArchive:
            move(7, 12);
            break;
        }
        
        refresh();
        
        /// input ///
        key = getch();

        if(editing == kReadOnly) {
            if(key == 16 || key == KEY_UP) {
                if(readonly == kNoChange) {
                    readonly = kOff;
                }
                else if(readonly == kOff) {
                    readonly = kOn;
                }
            }
            else if(key == 14 || key == KEY_DOWN) {
                if(readonly == kOff) {
                    readonly = kNoChange;
                }
                else if(readonly == kOn) {
                    readonly = kOff;
                }
            }
            else if(key == 10 || key == 13) {
                editing = kHidden;
            }
            else if(key == 3 || key == 7 || key == 27) {
                cancel = true;
                break;
            }
        }
        else if(editing == kHidden) {
            if(key == 16 || key == KEY_UP) {
                if(hidden == kNoChange) {
                    hidden = kOff;
                }
                else if(hidden == kOff) {
                    hidden = kOn;
                }
            }
            else if(key == 14 || key == KEY_DOWN) {
                if(hidden == kOff) {
                    hidden = kNoChange;
                }
                else if(hidden == kOn) {
                    hidden = kOff;
                }
            }
            else if(key == 10 || key == 13) {
                editing = kSystem;
            }
            else if(key == 3 || key == 7 || key == 27) {
                editing = kReadOnly;
            }
        }
        else if(editing == kSystem) {
            if(key == 16 || key == KEY_UP) {
                if(asystem == kNoChange) {
                    asystem = kOff;
                }
                else if(asystem == kOff) {
                    asystem = kOn;
                }
            }
            else if(key == 14 || key == KEY_DOWN) {
                if(asystem == kOff) {
                    asystem = kNoChange;
                }
                else if(asystem == kOn) {
                    asystem = kOff;
                }
            }
            else if(key == 10 || key == 13) {
                editing = kArchive;
            }
            else if(key == 3 || key == 7 || key == 27) {
                editing = kHidden;
            }
        }
        else if(editing == kArchive) {
            if(key == 16 || key == KEY_UP) {
                if(archive == kNoChange) {
                    archive = kOff;
                }
                else if(archive == kOff) {
                    archive = kOn;
                }
            }
            else if(key == 14 || key == KEY_DOWN) {
                if(archive == kOff) {
                    archive = kNoChange;
                }
                else if(archive == kOn) {
                    archive = kOff;
                }
            }
            else if(key == 10 || key == 13) {
                editing = kOK;
            }
            else if(key == 3 || key == 7 || key == 27) {
                editing = kSystem;
            }
        }
        else if(editing == kOK) {
            if(key == 'y' || key == 'Y' || key == 10 || key == 13) {
                break;
            }
            else if(key == 'n' || key == 'N') {
                cancel = true;
                break;
            }
            else if(key == 3 || key == 7 || key == 27) {
                editing = kArchive;
            }
        }
    }
    
    endwin();

    if(!cancel) {
        for(int i=1; i<argc; i++) {
            if(!(readonly == kNoChange && hidden == kNoChange && asystem == kNoChange && archive == kNoChange)) {
                char cmd[1024];
                sprintf(cmd, "output = `attrib '%s'`; s = output.split; if s[s.size-2] == \"-\" then nil else result = []; result[0] = (output[0]==32)?false:true; result[1] = (output[3]==32)?false:true; result[2]=(output[4]==32)?false:true; result[3]=(output[5]==32)?false:true; result end", argv[i]);
                VALUE attrib = rb_eval_string(cmd);
                
                if(attrib != Qnil) {
                    bool f_readonly = false;
                    bool f_archive = false;
                    bool f_system = false;
                    bool f_hidden = false;
                    
                    if(rb_ary_entry(attrib, 3) == Qtrue) {  // readonly
                        f_readonly = true;
                    }
                    if(rb_ary_entry(attrib, 0) == Qtrue) {  // archive
                        f_archive = true;
                    }
                    if(rb_ary_entry(attrib, 1) == Qtrue) {  // asystem
                        f_system = true;
                    }
                    if(rb_ary_entry(attrib, 2) == Qtrue) {  // hidden
                        f_hidden = true;
                    }
                    
                    char cmd2[1024];
                    sprintf(cmd2, "attrib.exe -A -S -H -R '%s'", argv[i]);
                    system(cmd2);
                    
                    sprintf(cmd2, "attrib.exe ");
                    if(readonly == kOn || (readonly == kNoChange && f_readonly)) {
                        strcat(cmd2, "+R ");
                    }
                    else {
                        strcat(cmd2, "-R ");
                    }
                    if(hidden == kOn || (hidden == kNoChange && f_hidden)) {
                        strcat(cmd2, "+H ");
                    }
                    else {
                        strcat(cmd2, "-H ");
                    }
                    if(asystem == kOn || (asystem == kNoChange && f_system)) {
                        strcat(cmd2, "+S ");
                    }
                    else {
                        strcat(cmd2, "-S ");
                    }
                    if(archive == kOn || (archive == kNoChange && f_archive)) {
                        strcat(cmd2, "+A ");
                    }
                    else {
                        strcat(cmd2, "-A ");
                    }
                    sprintf(cmd2 + strlen(cmd2), "'%s'", argv[i]);
                    
                    system(cmd2);
                }
            }
        }
    }

    return 0;
}
