//tran control
void add_tran();
void print_tran(void * ddb, int cur, int end,struct Map* map);
void * showTran(void * ddb,int index);
struct Map* sortTrans(void * ddb,int choice);

void tran_control(){
    struct transaction tran = read_db_tran();
    int choice;
    do{
        char buf[1024];
        welcome_message(buf);
        sprintf(buf+strlen(buf),"Transaction control\n");
        choice = choices_selecter((char*[]){
            "List transaction",
		    "new transaction"
        },2,buf);
        switch(choice){
             case 1:;
                char * SortItems[] = {
                    "Date&Time",
                    "product(barcode)",
                    "quantity",
                    "total",
                };
                lister(&tran,NULL,tran.db.row_count,"Transaction",SortItems,4,print_tran,sortTrans,showTran);
                break;
            case 2:
                add_tran();
                break;
            default:
                break;
        }
    }while(choice != 3);
}

void print_tran(void * ddb, int cur, int end,struct Map* map){
    struct transaction db = *((struct transaction*)ddb);
    printf("%-5s%-15s%-10s%-10s%-10s%-10s%-10s%-10s\n","No.","Date","Time","Barcode","ID","Price","Quantity","Total");
    for (int i = cur; i < end; i++)
    {
        if(map != NULL){
            int index = map[i].key;
            double total = db.row[index].price * db.row[index].quantity;
            //reconstuct date and time and print all transaction info out
            char date[11];
            char time[9];
            sprintf(date,"%02d-%02d-%04d",db.row[index].date.day,db.row[index].date.month,db.row[index].date.year);
            sprintf(time,"%02d:%02d:%02d",db.row[index].time.hour,db.row[index].time.minute,db.row[index].time.second);
            printf("%-5d%-15s%-10s%-10ld%-10ld%-10.2lf%-10d%-10.2lf\n",i+9,date,time,db.row[index].barcode,db.row[index].id,db.row[index].price,db.row[index].quantity,total);
        }else{
            double total = db.row[i].price * db.row[i].quantity;
            //reconstuct date and time and print all transaction info out
            char date[11];
            char time[9];
            sprintf(date,"%02d-%02d-%04d",db.row[i].date.day,db.row[i].date.month,db.row[i].date.year);
            sprintf(time,"%02d:%02d:%02d",db.row[i].time.hour,db.row[i].time.minute,db.row[i].time.second);
            printf("%-5d%-15s%-10s%-10ld%-10ld%-10.2lf%-10d%-10.2lf\n",i+9,date,time,db.row[i].barcode,db.row[i].id,db.row[i].price,db.row[i].quantity,total);
        }
    }
}
//show trans

struct transaction update_tran(struct transaction db,int index);
struct transaction remove_tran(struct transaction db,int index);

void * showTran(void * ddb,int index){
    struct transaction db = *((struct transaction*)ddb);
    int choice;
    do{
        char buff[1024];
        sprintf(buff,"Transaction detail\n");
        double total = db.row[index].price * db.row[index].quantity;
        //reconstuct date and time and print all transaction info out
        char date[11];
        char time[9];
        sprintf(date,"%02d-%02d-%04d",db.row[index].date.day,db.row[index].date.month,db.row[index].date.year);
        sprintf(time,"%02d:%02d:%02d",db.row[index].time.hour,db.row[index].time.minute,db.row[index].time.second);
        sprintf(buff+strlen(buff),"%-15s%-10s%-10s%-10s%-10s%-10s%-10s\n","Date","Time","Barcode","ID","Price","Quantity","Total");
        sprintf(buff+strlen(buff),"%-15s%-10s%-10ld%-10ld%-10.2lf%-10d%-10.2lf\n",date,time,db.row[index].barcode,db.row[index].id,db.row[index].price,db.row[index].quantity,total);    
        choice = choices_selecter((char*[]){
            "Edit transaction",
            "Delete transaction",
        },2,buff);
        switch(choice){
            case 1:
                db = update_tran(db,index);
                break;
            case 2:
                db = remove_tran(db,index);
                break;
            case 3:
                break;
            default:
                printf("Invalid Choice\n");
                break;
        }
    }while(choice != 3);
    void * re = malloc(sizeof(db));
    memcpy(re,&db,sizeof(db));
    return re;
}

//tran controls
void add_tran(){
    char* temp;
    struct transaction_row* row = (struct transaction_row*)malloc(sizeof(struct transaction_row));
    char check;
    printf("Use current date time? (y/n): ");
    fflush_stdin();
    scanf("%c",&check);
    if(check == 'y'){
        row->date = get_date();
        row->time = get_time();
    }else{
        if( !item_inputer("date:day",INT,&row->date.day,false) ||
            !item_inputer("date:month",INT,&row->date.month,false) ||
            !item_inputer("date:year",INT,&row->date.year,false) ||
            !item_inputer("time:hour",INT,&row->time.hour,false) ||
            !item_inputer("time:minute",INT,&row->time.minute,false) ||
            !item_inputer("time:second",INT,&row->time.second,false) 
        ){
            free(row);
            return;
        }
    }
    if (
        !item_inputer("price",DOUBLE,&row->price,false) ||
        !item_inputer("quantity",INT,&row->quantity,false) ||
        !item_inputer("ID",LONG,&row->id,false) ||
        !item_inputer("barcode",LONG,&row->barcode,false)
    ){
        free(row);
        return;
    }
    if(!row || !append_transaction_db(row)){
        printf("Failed to add item\n");
    }else{
        printf("Item added\n");
    }
    printf("press any key to continue\n");
    fflush_stdin();
    getchar();


}

struct transaction update_tran(struct transaction db,int index){
    char temp[100];
    printf("Update transaction(empty value to not change the value)\n");
    char date[11],time[9];
    sprintf(date,"%02d-%02d-%04d",db.row[index].date.day,db.row[index].date.month,db.row[index].date.year);
    sprintf(time,"%02d:%02d:%02d",db.row[index].time.hour,db.row[index].time.minute,db.row[index].time.second);
    printf("%-15s%-10s%-10s%-10s%-10s%-10s\n","Date","Time","Barcode","ID","Price","Quantity");
    printf("%-15s%-10s%-10ld%-10ld%-10.2lf%-10d\n",date,time,db.row[index].barcode,db.row[index].id,db.row[index].price,db.row[index].quantity);    
    
    item_inputer("Date:day",INT,&db.row[index].date.day,true);
    item_inputer("Date:month",INT,&db.row[index].date.month,true);
    item_inputer("Date:year",INT,&db.row[index].date.year,true);
    item_inputer("Time:hour",INT,&db.row[index].time.hour,true);
    item_inputer("Time:minute",INT,&db.row[index].time.minute,true);
    item_inputer("Time:second",INT,&db.row[index].time.second,true);
    item_inputer("Price",DOUBLE,&db.row[index].price,true);
    item_inputer("Quantity",INT,&db.row[index].quantity,true);
    item_inputer("ID",LONG,&db.row[index].id,true);
    item_inputer("Barcode",LONG,&db.row[index].barcode,true);
    
    if(unlikely(!update_db_tran(db))){
        printf("Failed to update transaction\n");
        exit(1);//exit program to prevent errors
    }else{
        printf("Transaction updated\n");
    }
    printf("press any key to continue\n");
    fflush_stdin();
    getchar();

    return db;
}

struct transaction remove_tran(struct transaction db,int index){
    db.row[index].isdeleted = true;
    if(unlikely(!update_db_tran(db))){
        printf("Failed to delete transaction\n");
        exit(1);//exit program to prevent errors
    }else{
        printf("Transaction deleted\n");
    }
    printf("press any key to continue\n");
    fflush_stdin();
    getchar();

    return read_db_tran();
} 

//sort transaction

struct Map* sortTrans(void * ddb,int choice){
    struct transaction db = *((struct transaction*)ddb);
    struct Map *map = malloc(sizeof(struct Map) * db.db.row_count);
    printf("l");
    for (int i = 0; i < db.db.row_count; i++){
        map[i].key = i;
        switch(choice){
            case 1:
            case 2:;
                long long temp = (long long)db.row[i].time.second+ db.row[i].time.minute*60 + db.row[i].time.hour*3600 + db.row[i].date.day*86400 + db.row[i].date.month*2592000 + db.row[i].date.year*31104000;
                long long* tempstar = malloc(sizeof(long long));
                *tempstar = temp;
                map[i].value = (void*)tempstar;
                break;

            case 3:
            case 4:;
                long* tempstar2 = malloc(sizeof(long));
                *tempstar2 = db.row[i].barcode; 
                map[i].value = (void*)tempstar2;
                break;
            case 5:
            case 6:;
                int* tempstar3 = malloc(sizeof(int));
                *tempstar3 = db.row[i].quantity;
                map[i].value = (void*)tempstar3;
                break;
            case 7:
            case 8:;
                long temp4 = lround(db.row[i].price * db.row[i].quantity * 10000);//clear all decimal places
                long* tempstar4 = malloc(sizeof(long));
                *tempstar4 = temp4;
                map[i].value = (void*)tempstar4;
                break;
        }
    }
    switch (choice){
        case 1:
        case 3:
        case 5:
        case 7:
            qsort(map, db.db.row_count, sizeof(struct Map), compare_decending);
            break;
        case 2:
        case 4:
        case 6:
        case 8:
            qsort(map, db.db.row_count, sizeof(struct Map), compare_ascending);
            break;
    }
    return map;
}
