//invetory control
void add_item();
void remove_item(struct inventory db,int index);
void update_item(struct inventory db,int index);
void * item_control(void * ddb,int index);
char * show_item_admin(struct inventory db,int index);
void * show_item(void * ddb,int index);
void print_page(void * ddb, int cur, int end,struct Map* map);
struct Map* sortItems(void * ddb, int sort);
void search_item(void * (*showitem)(void *,int));
void inv_control(){
        int choice = 0;
        do{
        char buf[1024];
        welcome_message(buf);
        sprintf(buf+strlen(buf),"Inventory control\n");
        choice = choices_selecter((char*[]){
            "List(allow all operation include add)",
        	"Add item(shortcut to add item)",
            "Search item"
        },3,buf);
        switch (choice){
            case 1:;//list
                //add a new element with product name new item
                //for item control
                struct inventory db = read_db_invt();   
                db.row = (struct inventory_row *)realloc(db.row, sizeof(struct inventory_row) * (db.db.row_count + 1));
                db.db.row_count += 1;
                strcpy(db.row[db.db.row_count - 1].product,"CREATE NEW ITEM");
                db.row[db.db.row_count - 1].barcode = -1024;//IMPORTANT: -1024 is reserved for new item
                char * SortItems[] = {
                    "Name",
                    "Price",
                    "Brand",
                    "Category",
                };
                lister(&db,NULL,db.db.row_count,"Inventory",SortItems,4,print_page,sortItems,item_control);
                break;
            case 2://add item
                add_item();
                break;
            case 3:
                search_item(item_control);
                break;
            case 4://exit
                break;
            default://should not happen
                printf("Invalid choice\n");
                break;
        }
        }while(choice != 4);
}

char * show_item_admin(struct inventory db,int index){
	char * output = (char*)malloc(sizeof(char) * 2048);
    sprintf(output,"Product: %s\n", db.row[index].product);
    sprintf(output+strlen(output),"Catergory: %s\n", db.row[index].category);// strlen to add offset
    sprintf(output+strlen(output),"Brand: %s\n", db.row[index].brand);
    sprintf(output+strlen(output),"Price: $%lf\n", db.row[index].price);
    sprintf(output+strlen(output),"Stock: %d\n", db.row[index].stock);
    sprintf(output+strlen(output),"Barcode: %ld\n",db.row[index].barcode);
    return output;
}
//for normal user
void * show_item(void * ddb,int index){
    struct inventory db = *((struct inventory*)ddb);
    Cls();
    printf("Product: %s\n", db.row[index].product);
    printf("Catergory: %s\n", db.row[index].category);
    printf("Brand: %s\n", db.row[index].brand);
    printf("Price: $%lf\n", db.row[index].price);
    printf("Stock: %d\n", db.row[index].stock);
    printf("Barcode: %ld\n",db.row[index].barcode);
    printf("Press any key to return to the list\n");
    fflush_stdin();
    getchar();
    return ddb;
}

void print_page(void * ddb, int cur, int end,struct Map* map){
    struct inventory db = *((struct inventory*)ddb);
    printf("%-5s%-15s%-15s%-10s%-10s%-10s%-10s\n","No.","Product","Brand","Category","Price","Stock","Barcode");
    for (int i = cur; i < end; i++)
    {
        if(map != NULL){
            int index = map[i].key;
            printf("%-5d%-15s%-15s%-10s%-10.2lf%-10d%-10ld\n",i+9,StringCompression(db.row[index].product,13),StringCompression(db.row[index].brand,13),StringCompression(db.row[index].category,8),db.row[index].price,db.row[index].stock,db.row[index].barcode);
        }
        else{
            printf("%-5d%-15s%-15s%-10s%-10.2lf%-10d%-10ld\n",i+9,StringCompression(db.row[i].product,13),StringCompression(db.row[i].brand,13),StringCompression(db.row[i].category,8),db.row[i].price,db.row[i].stock,db.row[i].barcode);
        }
    }
}

void * item_control(void * ddb,int index){
    struct inventory db = *((struct inventory*)ddb);
    int choice = 0;
    if(db.row[index].barcode == -1024){//new item
        add_item();
        struct inventory temp = read_db_invt();//reappend new item at back
        temp.row = (struct inventory_row *)realloc(temp.row, sizeof(struct inventory_row) * (temp.db.row_count + 1));
        temp.db.row_count += 1;
        strcpy(temp.row[temp.db.row_count - 1].product,"CREATE NEW ITEM");
        temp.row[temp.db.row_count - 1].barcode = -1024;//IMPORTANT: -1024 is reserved for new item
        void * re = malloc(sizeof(temp));
        memcpy(re,&temp,sizeof(temp)); 
        return re;
    }
    char * item = show_item_admin(db,index);
    char welcome[4096];
    strcpy(welcome,item);
    strcat(welcome,"Operations\n");
    do
    {
		choice = choices_selecter((char*[]){
            "update item",
        	"remove item"
        },2,welcome);
        switch (choice)
        {
            case 1:
                update_item(db,index);
                break;
            case 2:
                remove_item(db,index);
                break;
            default:
                break;
        }
    } while (choice != 3&&choice != 2);
    struct inventory temp = read_db_invt();
    temp.row = (struct inventory_row *)realloc(temp.row, sizeof(struct inventory_row) * (temp.db.row_count + 1));
    temp.db.row_count += 1;
    strcpy(temp.row[temp.db.row_count - 1].product,"CREATE NEW ITEM");
    temp.row[temp.db.row_count - 1].barcode = -1024;//IMPORTANT: -1024 is reserved for new item
    void * re = malloc(sizeof(temp));
    memcpy(re,&temp,sizeof(temp)); 
    return re;
}

void add_item(){
    Cls();
    printf("Add new item\n");
    struct inventory_row *item = (struct inventory_row *)malloc(sizeof(struct inventory_row));
    if(!item_inputer("name",STRING,&item->product,false)       ||
        !item_inputer("brand",STRING,&item->brand,false)       ||
        !item_inputer("category",STRING,&item->category,false) ||
        !item_inputer("price",DOUBLE,&item->price,false)       ||
        !item_inputer("stock",INT,&item->stock,false)        ||
        !item_inputer("barcode",LONG,&item->barcode,false)     
    ){
        free(item);
        return;
    }
    if(item == NULL || !append_inventory(item)){
        printf("Failed to add item\n");
    }else{
        printf("Item added\n");
    }
    printf("press any key to continue\n");
    fflush_stdin();
    getchar();
}

void update_item(struct inventory db,int index){
    char temp[100];
    printf("Update item(empty value to not change the value)\n");
    printf("Name: %s\n", db.row[index].product);
    printf("Brand: %s\n", db.row[index].brand);
    printf("Catergory: %s\n", db.row[index].category);
    printf("Price: $%lf\n", db.row[index].price);
    printf("Stock: %d\n", db.row[index].stock);
    printf("Barcode: %ld\n",db.row[index].barcode);
    item_inputer("name",STRING,&db.row[index].product,true);
    item_inputer("brand",STRING,&db.row[index].brand,true);     
    item_inputer("category",STRING,&db.row[index].category,true);
    item_inputer("stock",DOUBLE,&db.row[index].price,true);
    item_inputer("barcode",LONG,&db.row[index].barcode,true);
    if(!update_db_invt(db)){
        printf("Failed to update item\n");
        exit(1);
    }else{
        printf("Item updated\n");
    }
    printf("press any key to continue\n");
    fflush_stdin();
    getchar();
}

void remove_item(struct inventory db,int index){
    printf("Remove item\n");
    printf("Are you sure you want to remove this item? (y/n)\n");
    char choice;
    fflush_stdin();
    scanf("%c", &choice);
    db.row[index].isdeleted = true;
    if(choice == 'y'){
        if(!update_db_invt(db)){
            printf("Failed to remove item\n");
        }else{
            printf("Item removed\n");
        }
    }else{
        printf("Item not removed\n");
    }
    printf("press any key to continue\n");
    fflush_stdin();
    getchar();
}

struct Map* sortItems(void * ddb, int sort){
    struct inventory db = *((struct inventory*)ddb);
    struct Map *map = malloc(sizeof(struct Map) * db.db.row_count -1);
    for (int i = 0; i < db.db.row_count-1; i++){
        map[i].key = i;

        switch(sort){
            case 1:
            case 2:
                map[i].value = (void*)db.row[i].product;
                break;

            case 3:
            case 4:;
                double price = db.row[i].price * 100;
                double * price_star = malloc(sizeof(long));
                *price_star = price;
                map[i].value = (void*)price_star;//presume there is no price contain  0.001
                break;
            case 5:
            case 6:
                map[i].value = (void*)db.row[i].brand;
                break;
            case 7:
            case 8:
                map[i].value = (void*)db.row[i].category;
                break;
        }
    }
    switch (sort){
        case 1:
        case 5:
        case 7:
            qsort(map, db.db.row_count-1, sizeof(struct Map), compare_decending_str);
            break;
        case 2:
        case 6:
        case 8:
            qsort(map, db.db.row_count-1, sizeof(struct Map), compare_ascending_str);
            break;
        case 3:
            qsort(map, db.db.row_count-1, sizeof(struct Map), compare_decending);
            break;
        case 4:
            qsort(map, db.db.row_count-1, sizeof(struct Map), compare_ascending);
            break;
    }
    map = realloc(map, sizeof(struct Map) * db.db.row_count);
    map[db.db.row_count-1].key = db.db.row_count-1;
    return map;
}
