#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <iostream.h>
#include <fstream.h>

#include "e:\opt\common\timings.h"

int main(int argc, char *argv[])
{
    const int BUFCOUNT = 256;
    const int TOTAL_BUFFER = 4*1048576;
    const int INPUTLINESIZE = 1024;
    char InputLine[INPUTLINESIZE];
    char *Buffer[BUFCOUNT];
    int BufferSize[BUFCOUNT];
    int BufferCharCount[BUFCOUNT];
    int Displacement[BUFCOUNT];
    int TotalDisplacement[BUFCOUNT];
    char CurrentChar;
    char* InputFileName;
    char* OutputFileName;
    ifstream InputFile;
    ofstream OutputFile;
    int PassCount;
    int CurrentLength;
    int NewLength;
    int LineLength;
    char* OriginalInputFileName;
    char* OriginalOutputFileName;
    int TotalKeys = 0;
    int TotalData = 0;
    bool StatisticsDisplayed = false;
    int TotalWrites = 0;
    int i;
    double BufferRatio;

    if (argc < 4)
        {
        printf("Usage: zensort passcount infile outfile\n");
        exit(1);
        }
    else
        {
        PassCount = atoi(argv[1]);
        OriginalInputFileName = argv[2];
        OriginalOutputFileName = argv[3];
        }

char temp[100];
start_timing();

    for (int Pass = PassCount - 1; Pass >= 0; Pass --)
        {

        if ((PassCount - Pass) % 2 == 1)
            {
            InputFileName = OriginalInputFileName;
            OutputFileName = OriginalOutputFileName;
            }
        else
            {
            InputFileName = OriginalOutputFileName;
            OutputFileName = OriginalInputFileName;
            }

        InputFile.open(InputFileName,ios::in|ios::binary);
        OutputFile.open(OutputFileName,ios::out|ios::binary);

        for (i = 0; i < BUFCOUNT; i ++)
            {
            Displacement[i] = 0;
            TotalDisplacement[i] = 0;
            }

        while (true)
            {
            InputFile.getline(InputLine,INPUTLINESIZE);
            if (!InputFile)
                break;
            TotalKeys ++;
            LineLength = strlen(InputLine);
            if (Pass >= LineLength)
                CurrentChar = 0;
            else
                CurrentChar = InputLine[Pass];
            Displacement[CurrentChar] += LineLength + 1;
            }
        InputFile.close();

        for (i = 1; i < BUFCOUNT; i ++)
            {
            TotalDisplacement[i] = TotalDisplacement[i-1] + Displacement[i-1];
            }

        if (TotalData == 0)
           {
           for (i = 0; i < BUFCOUNT; i ++)
              {
              TotalData += Displacement[i];
              }
           BufferRatio = (double) TOTAL_BUFFER / TotalData;
           }

        for (i = 0; i < BUFCOUNT; i ++)
            {
            BufferSize[i] = (int) (BufferRatio*Displacement[i]);
            if (BufferSize[i] == 0)
              Buffer[i] = 0;
            else
              {
              Buffer[i] = new char[BufferSize[i]];
              memset(Buffer[i],0,BufferSize[i]);
              }
            BufferCharCount[i] = 0;
            }

if ((Pass == PassCount - 1) && StatisticsDisplayed == false)
  {
  printf("Total keys: %d\n", TotalKeys);
  printf("Total data: %d\n", TotalData);
  StatisticsDisplayed = true;
  }

sprintf(temp,"Finished counting on pass %d",PassCount-Pass);
timing(temp);

        InputFile.open(InputFileName,ios::in|ios::binary);

        while (true)
            {
            InputFile.getline(InputLine,INPUTLINESIZE);
            if (!InputFile)
                break;
            LineLength = strlen(InputLine)+1;
            strcpy(InputLine+LineLength-1,"\n");
            if (Pass >= LineLength-1)
                CurrentChar = 0;
            else
                CurrentChar = InputLine[Pass];
            CurrentLength = BufferCharCount[CurrentChar];
            NewLength =  CurrentLength + LineLength;
            if (NewLength >= BufferSize[CurrentChar])
                {
                OutputFile.seekp(TotalDisplacement[CurrentChar]);
                TotalDisplacement[CurrentChar] += CurrentLength;
                OutputFile.write(Buffer[CurrentChar],CurrentLength);
                TotalWrites ++;
                memset(Buffer[CurrentChar],0,BufferSize[CurrentChar]);
                BufferCharCount[CurrentChar] = 0;
                }
            strcpy(Buffer[CurrentChar]+BufferCharCount[CurrentChar],InputLine);
            BufferCharCount[CurrentChar] += strlen(InputLine);
            }

        for (i = 0; i < BUFCOUNT; i ++)
            {
            if (Buffer[i])
                {
                CurrentLength = BufferCharCount[i];
                if (CurrentLength > 0)
                    {
                    OutputFile.seekp(TotalDisplacement[i]);
                    OutputFile.write(Buffer[i],CurrentLength);
                    TotalWrites ++;
                    }
                }
            }
        InputFile.close();
        OutputFile.close();

        for (i = 0; i < BUFCOUNT; i ++)
            {
            delete [] Buffer[i];
            }

sprintf(temp,"Finished distributing on pass %d",PassCount-Pass);
timing(temp);
    }

    printf("Total writes: %d\n", TotalWrites);
    
    end_timing();

    return 0;
}

