/* VEC Reader - reads VEC and VE2 vector graphic files and displays them on the
   screen. The diashow function displays all VEC/VE2 files on disc one after
   another until a key is pressed.

   Version 4.2 */

#include <stdio.h>
#include <graphics.h>
#include <conio.h>
#include "forms2.h"
#include "convert.h"
#include "box.h"
#include "vecin2.h"
#define MaxFiles 100

typedef enum {actionCancel, actionDiashow, actionDisplayFile} t_action;


// Initializes the form elements. This procedure is called from initForm().
void initFormElements(uint8_t formIdx) {

    switch (formIdx) {
        case 1:
            // Field 1
            addField(ftFileName, 14, "Name of VEC/VE2 file", 2, 6, 24, 6, false);
            
            // Button 1
            newAndLinkWithPrevElement();
            addButton(ok, 40, 5, 17, "OK");

            // Field 2
            newAndLinkWithPrevElement();
            addField(ftNumNatural, 3, "Diashow pause", 2, 9, 17, 9, false);

            // Button 2
            newAndLinkWithPrevElement();
            addButton(ok, 40, 8, 17, "Start diashow");

            // Button 3
            newAndLinkWithPrevElement();
            addButton(cancel, 2, 16, 15, "Cancel");

            break;
    }
}


// Plots multiple dots.
void polyPlot() {
    int i;
    int x, y;
    uint8_t count;
    
    count = readDotCount();
    //printf("polyPlot #%d", count); // DEBUG
    
    for (i = 0; i < count; i++) {
        x = readX();
        y = readY();
        if ((unsigned int) x < 720 && (unsigned int) y < 256) {
            //printf(" plot(%d, %d)", x, y); // DEBUG
            plot(x, y);
        }
    }
}


// Draws multiple connected lines.
void polyLine() {
    uint8_t count;
    uint8_t i;
    int x, y;
    
    count = readDotCount();
    //printf("polyLine #%d", count); // DEBUG
    
    if (count > 0) {
        x = readX();
        y = readY();
        if ((unsigned int) x < 720 && (unsigned int) y < 256) {
            //printf(" plot(%d, %d)", x, y); // DEBUG
            plot(x, y);
        }
        
        for (i = 1; i < count; i++) {
            x = readX();
            y = readY();
            if ((unsigned int) x < 720 && (unsigned int) y < 256) {
                //printf(" drawto(%d, %d)", x, y); // DEBUG
                drawto(x, y);
            }
        }
    }
}
/*
void polyLine2() {
    int i;
    int x1, y1, x2, y2;
    uint8_t count;
    
    count = readDotCount();
//    printf("polyLine - #dots: %d\n", count); // DEBUG
    
    if (count > 0) {
        x1 = readX();
        y1 = readY();
//        printf("x1: %d  y1: %d\n", x1, y1); // DEBUG
        
        for (i = 1; i < count; i++) {
            x2 = readX();
            y2 = readY();
//            printf("x1: %d  y1: %d  x2: %d  y2: %d\n", x1, y1, x2, y2); // DEBUG
//            waitForKey(); // DEBUG
            if (x1 >= 0 && x1 < 720 && y1 >= 0 && y1 < 256 &&
                x2 >= 0 && x2 < 720 && y2 >= 0 && y2 < 256) {
                draw(x1, y1, x2, y2);
            }
            x1 = x2;
            y1 = y2;
        }
    }
}
*/

// Reads and displays a VEC file.
void readVecFile(char *fileName) {
    uint8_t fileType;   // 1=VEC, 2=VE2
    uint8_t opCode;
    int x1, y1;
    int x2, y2;
    VE2Header *header;

    if (openVecFile(fileName) == ErrOk) {
        fileType = readFileType();
//        printf("fileType: %d\n\n", fileType); // DEBUG
    
        if (fileType != 0) {
            if (fileType == 2) {
                header = readVe2Header();
/*
                printf("minX: %d\n", header->minX);                           // DEBUG
                printf("maxX: %d\n", header->maxX);                           // DEBUG
                printf("minY: %d\n", header->minY);                           // DEBUG
                printf("maxY: %d\n", header->maxY);                           // DEBUG
                printf("targetResolutionX: %d\n", header->targetResolutionX); // DEBUG
                printf("targetResolutionY: %d\n", header->targetResolutionY); // DEBUG
                printf("bytesXCoord: %d\n", header->bytesXCoord);             // DEBUG
                printf("bytesYCoord: %d\n", header->bytesYCoord);             // DEBUG
                printf("profileFlags: %d\n\n", header->profileFlags);         // DEBUG
                waitForKey();                                                 // DEBUG
*/
            }
            do {
                opCode = readOpCode();
                //printf("opCode: %d  ", opCode); // DEBUG
                switch (opCode) {
                    case 0: // Dot
                        x1 = readX();
                        y1 = readY();
                        if ((unsigned int) x1 < 720 && (unsigned int) y1 < 256) {
                            //printf("plot(%d, %d)", x1, y1); // DEBUG
                            plot(x1, y1);
                        }
                        break;
                    case 1: // Line
                        x1 = readX();
                        y1 = readY();
                        x2 = readX();
                        y2 = readY();
                        if ((unsigned int) x1 < 720 && (unsigned int) y1 < 256 &&
                            (unsigned int) x2 < 720 && (unsigned int) y2 < 256) {
                            //printf("draw(%d, %d, %d, %d)", x1, y1, x2, y2); // DEBUG
                            draw(x1, y1, x2, y2);
                        }
                        break;
                    case 2: // Box
                        x1 = readX();
                        y1 = readY();
                        x2 = readX();
                        y2 = readY();
                        if ((unsigned int) x1 < 720 && (unsigned int) y1 < 256 &&
                            (unsigned int) x2 < 720 && (unsigned int) y2 < 256) {
                            //printf("drawb(%d, %d, %d, %d)", x1, y1, x2 - x1, y2 - y1); // DEBUG
                            drawb(x1, y1, x2 - x1, y2 - y1);
                        }
                        break;
                    case 3: // Square
                        x1 = readX();
                        y1 = readY();
                        x2 = readMax(); // width
                        if ((unsigned int) x1 < 720 && (unsigned int) y1 < 256 &&
                            (unsigned int) x2 < 720) {
                            //printf("drawb(%d, %d, %d, %d)", x1, y1, x2, x2); // DEBUG
                            drawb(x1, y1, x2, x2);
                        }
                        break;
                    case 4: // Ellipse
                        x1 = readX();
                        y1 = readY();
                        x2 = readX(); // radius x
                        y2 = readY(); // radius y
                        //printf("ellipse(%d, %d, %d, 0)", x1, y1, x2); // DEBUG
                        circle(x1, y1, x2, 0); // TODO create ellipse function
                        break;
                    case 5: // Circle
                        x1 = readX();
                        y1 = readY();
                        x2 = readMax(); // radius
                        //printf("circle(%d, %d, %d, 0)", x1, y1, x2); // DEBUG
                        circle(x1, y1, x2, 0);
                        break;
                    case 10: // Multi-Dot
                        polyPlot();
                        break;
                    case 11: // Multi-Line
                        polyLine();
                        break;
                    case 12: // Polygon-Fill
                        polyLine(); // TODO polyFill
                        break;
                    case 99: // End
                        break;
                    default:
                        printf("Unknown OpCode: %d\n", opCode);
                }
                //putchar('\n'); waitForKey(); // DEBUG
            } while(opCode != 99);
        }
        else {
          printf("File %s is not a VEC/VE2 file.\n", fileName);
        }
        closeVecFile();
    }
    else {
        printf("Could not open %s\n", fileName);
    }
}


// Copies a filename from the DMA array to the return value.
char *dmaToFileName(int start, char *dma) {
  
    int loop;
    char ch;
    char buf[13];
    char *bufp;
    char *fileName;
    
    bufp = buf;
    
    for (loop = start + 1; loop <= start + 8; loop++) { // copy filename
        ch = dma[loop];
        if (ch != ' ') {
            *bufp = ch;
            bufp++;
        }
    }
    *bufp = '.';
    bufp++;
    
    for (loop = start + 9; loop <= start + 11; loop++) { // copy extension
        ch = dma[loop];
        if (ch != ' ') {
            *bufp = ch;
            bufp++;
        }
    }
    *bufp = '\0';
    fileName = malloc(strlen(buf) + 1);
    strcpy(fileName, buf);
    
    return fileName;
}


/* Reads VEC/VE2 filenames into the fileNames array.
   Returns the number of files found. */
int readDirectory(char **fileNames) {

    int error, loop, start;
    static char *fcb;
    char dma[267];
    int idx;
    char *fileName;

    fcb = (char *) 0x0060;
    error = bdos(CPM_SDMA, (int) dma);
    fcb[0] = '\0';
    // filter: files with extension mask VE? only
    for (loop = 1; loop < 9; loop++) {
        fcb[loop] = '?';
    }
    fcb[ 9] = 'V';
    fcb[10] = 'E';
    fcb[11] = '?'; // 'C' or '2' expected

    idx = 0;
    error = bdos(CPM_FFST, (int) fcb);
    if (error != -1) {
        start = error * 32;
        fileName = dmaToFileName(start, dma);
        fileNames[idx++] = fileName;
    }
    
    do {
        error = bdos(CPM_FNXT, (int) fcb);
        start = error * 32;
        if (error != -1) {
            fileName = dmaToFileName(start, dma);
            fileNames[idx++] = fileName;
            if (idx >= MaxFiles) {
              error = -1; // exit loop
            }
        }
    } while (error != -1);

    return idx;
}


// Displays a diashow.
void diashow(int diashowDelay) {
    bool run;
    int i, j;
    char *fileNames[MaxFiles];
    char *fileName;
    int fileCount;

    // init fileNames array
    for (i = 0; i < MaxFiles; i++) {
        fileNames[i] = NULL;
    }
    
    fileCount = readDirectory(fileNames);

    if (fileCount > MaxFiles) {
        fileCount = MaxFiles;
    }
    run = true;

    while (run) {
        for (i = 0; i < fileCount; i++) {
            fileName = fileNames[i];
            clearScreen();
            printf("filename: %s\n", fileName); // DEBUG
            readVecFile(fileName);
            for (j = 0; j < diashowDelay; j++) {
                msleep(1000);
                if (kbhit()) {
                    run = false;
                    break;
                }
            }
            if (!run) {
                break;
            }
        }
    }
    
    // clean up fileNames array
    for (int i = 0; i < MaxFiles; i++) {
        if (fileNames[i] != NULL) {
            free(fileNames[i]);
        }
    }
}


// The main method.
int main(int argc, char *argv[]) {
    
    char fileName[15];
    int diashowDelay; // Delay between diashow pictures in seconds
    t_action action;
    int intValue;
    Field *formField;
    bool processing;
    
    //printf("main: %x  fileName: %x\n", main, fileName); getch(); // DEBUG
    
    *fileName = '\0';
    
    do {
        // get the name of the VEC/VE2 file, or the diashow parameters, respectively
        diashowDelay = 4; // initialize to 4 seconds
        if (argc > 1) {
            strcpy(fileName, argv[1]); // first commandline parameter treated as filename
            if (strcmp(fileName, "D") == 0 || strcmp(fileName, "d") == 0) {
                action = actionDiashow;
            }
            else {
                action = actionDisplayFile;
            }
            
            if (argc > 2) {
                diashowDelay = atoi(argv[2]);
                if (diashowDelay == 0) { // invalid delay parameter
                    diashowDelay = 4; // default delay between pictures of 4 seconds
                }
            }
        }
        else {
            clearScreen();
            drawBox(0, 0, 90, 3);
            gotoXY(27, 1);
            printf("VEC/VE2 file reader V4.2 by Bernd Bock");
            gotoXY(21, 9);
            printf("seconds");

            setMessageLine(22);
            initForm(1);
            processing = true;
        
            do {
                processForm();

                if (formCancelled()) {
                    action = actionCancel;
                    processing = false;
                }
                else {
                    if (isActivated(2)) { // Button 2 = Start diashow
                        action = actionDiashow;
                        formField = getField(2); // Field 2 = Diashow pause
                        intValue = stringToInteger(formField->txt);
                        if (intValue > 0) {
                            diashowDelay = intValue;
                        }
                        processing = false;
                    }
                    else { // Ok button activated
                        action = actionDisplayFile;
                        formField = getField(1); // Field 1 = VEC/VE2 filename
                        strcpy(fileName, formField->txt);
                        if (*fileName == '\0') { // empty string
                            gotoXY(0, 21); printf("Please enter a VEC/VE2 filename.");
                        }
                        else {
                            processing = false;
                        }
                    }
                }
            } while (processing);
            
            destroyForm(1);
        }
      
        statusBarOff();
        clearScreen();
        hideCursor();
      
        switch (action) {
            case actionDiashow:
                diashow(diashowDelay);
                break;
            case actionDisplayFile:
                readVecFile(fileName);
                break;
        }
      
        if (action != actionCancel) {
            beep();
            waitForKey();
        }
        
        statusBarOn();
        showCursor();
    } while (action != actionCancel && argc < 2);
  
    return 0;
}
