/*
    pngacidbath - PNG brute force optimizer
    Copyright (c) 2011 Drew D'Addesio ("Fatbag", <X-Fi6@phppoll.org>)

    Permission to use, copy, modify, and/or distribute this software for any
    purpose with or without fee is hereby granted, provided that the above
    copyright notice and this permission notice appear in all copies.

    THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
    WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
    MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
    ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
    WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
    ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
    OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/

#include "version.h"

#include <stdio.h>
#include <opencl.h>

const char *infile = NULL, *outfile = NULL, *logfile = NULL; //NULL -> read from stdin / write to stdout, or (log file) ignore
const char bool_shortnames[] = { 's', 'n', 'q', 'v', 'h', 'V' };
const char *bool_longnames[] = { "strip", "no-gpu", "quiet", "verbose", "help", "version" };
enum bool_arg { OPTION_STRIP, OPTION_NOGPU, OPTION_QUIET, OPTION_VERBOSE, OPTION_HELP, OPTION_VERSION };
bool bool_option[6] = {0};
const char optimize_names[] = { 'd', 'f', 'p', 't' };
enum optimize_arg { OPTION_DEFLATE, OPTION_FILTER, OPTION_PALETTE, OPTION_TYPE };
int optimize_option[4] = {3, 3, 3, 3};

int main(int argc, char *argv[])
{
    if(argc == 1){
        bool_option[OPTION_HELP] = 1;
    }else{
        //
        // Argument parsing
        //
        int i = 1;
        bool outfilespecified = false, logfilespecified = false;

        do{ //while ++i < argc
            bool isoption = false;
            if(argv[i][0] == '-'){
                if(argv[i][1] == '\0'){
                    if(i == argc-1){
                        break; //Read from stdin
                    } //else read from a file that starts with "- "
                }else if(argv[i][1] == '-'){
                    for(int x=0; x<6; x++){
                        if(!strcmp(argv[i]+2, bool_longnames[x])){
                            bool_option[x] = true;
                            isoption = true;
                            break;
                        }
                    }
                    if(isoption) continue;
                }else{
                    if(argv[i][2] == '\0'){ //one-letter option
                        if(argv[i][1] == 'o'){
                            if(i != argc-1){
                                i++;
                                outfilespecified = true;
                                outfile = (argv[i][0] == '-' && argv[i][1] == '\0') ? NULL : argv[i];
                                continue;
                            }
                        }else if(argv[i][1] == 'l'){
                            if(i != argc-1){
                                i++;
                                logfilespecified = true;
                                logfile = (argv[i][0] == '-' && argv[i][1] == '\0') ? NULL : argv[i];
                                continue;
                            }
                        }else{
                            for(int x=0; x<6; x++){
                                if(argv[i][1] == bool_shortnames[x]){
                                    bool_option[x] = true;
                                    isoption = true;
                                    break;
                                }
                            }
                            if(isoption) continue;
                        }
                    }else{
                        if(argv[i][3] == '\0' && argv[i][2] >= '0' && argv[i][2] <= '3'){
                            for(int x=0; x<4; x++){
                                if(argv[i][1] == optimize_names[x]){
                                    optimize_option[x] = argv[i][2]-'0';
                                    isoption = true;
                                    break;
                                }
                            }
                            if(isoption) continue;
                        }
                    }
                }
            }

            //Made it this far; this argument is not an option
            //Combine all remaining strings into one string

            if(i == argc-1){
                infile = argv[i];
            }else{
                int namelength = 0;
                for(int x=i; x<argc; x++){
                    namelength += strlen(argv[x]) + 1;
                }
                char *infilestartpos = (char *) malloc(namelength);
                char *infilecurpos = infilestartpos;
                *infilecurpos = '\0';
                bool firstword = true;
                for(int x=i; x<argc; x++){
                    int arglength = strlen(argv[x]);
                    if(arglength){
                        if(firstword) firstword = false;
                        else *(infilecurpos++) = ' ';
                        memcpy(infilecurpos, argv[x], arglength);
                        infilecurpos += arglength;
                    }
                }
                *infilecurpos = '\0';
                infile = infilestartpos;
            }

            if(!outfilespecified) outfile = infile;

            break;
        } while(++i < argc);

        if(!logfilespecified){
            if(outfile == NULL){
                logfile = NULL;
            }else{
                int outnamelength = strlen(outfile);
                char *logfiletemp = (char *) malloc(outnamelength+9);
                memcpy(logfiletemp, outfile, outnamelength);
                memcpy(logfiletemp+outnamelength, ".pab.xml", 9);
                logfile = logfiletemp;
            }
        }
    }

    if(bool_option[OPTION_HELP]){
        printf(
            "Usage: pngacidbath [OPTIONS] [FILE]\n"
            "Losslessly reduce the size of a PNG image file.\n"
            "With no FILE, or when FILE is -, read from standard input.\n"
            "\n"
            "Optimization options:\n"
            "  -s, --strip       Reduce chunk structure to the bare minimum\n"
            "                    (IHDR, IDAT, and IEND)\n"
            "  -dN, -fN, -pN,    -d: DEFLATE compression\n"
            "    -tN             -f: Scanline filter search\n"
            "                    -p: Palette reordering\n"
            "                    -t: Image type search\n"
            "\n"
            "                    Levels:\n"
            "                    N: 3: brute force (default)\n"
            "                       2: decide quickly and intelligently\n"
            "                          (many rounds, best picked)\n"
            "                       1: decide quickly and intelligently\n"
            "                          (single round)\n"
            "                       0: skip entirely (not recommended)\n"
            "\n"
            "Miscellaneous:\n"
            "  -o OUTFILE        Instead of overwriting contents to\n"
            "                    the input file, write contents to OUTFILE\n"
            "                    (if OUTFILE is -, write to standard\n"
            "                    output)\n"
            "  -l LOGFILE        Create the \"left off\" log file under the\n"
            "                    name LOGFILE; by default, the name used is\n"
            "                    OUTFILE.pab.xml (if LOGFILE is -, do not\n"
            "                    leave a log file)\n"
            "  -n, --no-gpu      Do not use GPU\n"
            "  -q, --quiet       Print only progress and current best size\n"
            "  -v, --verbose     Print rounds performed and information\n"
            "                    regarding computation speed\n"
            "  -h, --help        Display this help and exit\n"
            "  -V, --version     Display version and licensing and exit\n"
            "\n"
            "Many computations are performed to find the smallest data that\n"
            "decompresses to the image data of the source PNG file. Your\n"
            "GPU will be used automatically if it's supported, unless\n"
            "specifically turned off.\n"
            "\n"
            "Report bugs to:\n"
            "<https://sourceforge.net/tracker/?group_id=558544&atid=2266128>"
        );
        return 0;
    }

    if(bool_option[OPTION_VERSION]){
        printf(
            "pngacidbath version " PAB_VERSION "\n"
            "Copyright (c) 2011 Drew D'Addesio (\"Fatbag\", <X-Fi6@phppoll.org>)\n"
            "\n"
            "Permission to use, copy, modify, and/or distribute this software for any\n"
            "purpose with or without fee is hereby granted, provided that the above\n"
            "copyright notice and this permission notice appear in all copies.\n"
            "\n"
            "This is free software. There is NO warranty; not even for MERCHANTABILITY\n"
            "or FITNESS FOR A PARTICULAR PURPOSE, to the extent permitted by law.\n"
            "\n"
            "pngacidbath home page: <http://pngacidbath.sf.net/>\n"
            "Report bugs to:\n"
            "<https://sourceforge.net/tracker/?group_id=558544&atid=2266128>"
        );
        return 0;
    }

    printf("Input file: %s\nOutput file: %s\nLog file: %s",
        (infile != NULL) ? infile : "standard input",
        (outfile != NULL) ? outfile : "standard output",
        (logfile != NULL) ? logfile : "None");
    return 0;
}