/********************************************************************************************
ezwSort.cpp
	Jim Millard
	for CO311

    EZwindows sort visualizations

********************************************************************************************/
#include "ezwSort.h"

#include <iostream>
#include <math.h>
#include <sys/timeb.h>
#include <ezwin.h>
#include <ray.h>

#include "ezwUtils.h"
#include "ezwWorst.h"
#include "ezwBubbl.h"
#include "ezw2wBub.h"
#include "ezwShell.h"
#include "ezwSelec.h"
#include "ezwInsrt.h"
#include "ezwQuick.h"


//global variables used by window placement routines (avoid this if possible!)
float clientX = winX - 1., clientY = winY - 1.; //display area for sorting
float tempX = winX - .5; //horizontal position used when swapped to a "temp" location
float baseline = clientY - 0.1; //Bottom edge of all bars

/*********************************************************************************************/

void Visualize(int A[], const int toSort, const sortchoice whichSort, const short load)
    {
    //set the counter so we're never "running off the cliff" with the array
    int count;
    if (toSort > MaxElements)
        count = MaxElements;
    else
        count = toSort;

    //adjust the windowing area based on the set of elements
    if (clientX/count > 1)
        {
        clientX = winX - clientX/count;
        tempX = winX - 0.5 * clientX/count;
        }

    const float scaleX = clientX/count;
    const float barWidth = scaleX * 0.9;
    
    int maxOfA = maxValue(A, count);
    int minOfA = minValue(A, count);
    const float scaleY = (baseline - barWidth) / (maxOfA - minOfA);
    const float intercept = (barWidth*maxOfA - baseline*minOfA) / (maxOfA - minOfA);

    SimpleWindow W("Visualize Sort Algorithms", winX, winY, Position(0.,0.));
    W.Open();

    //divide the client area up
    RefreshDisplay(W, "Sorting", Red);

    RaySegment* Display[MaxElements]; //array of pointer to RaySegment
    int i;
    for (i = 0; i < count; i++)
        {
        Position StartPoint((i+0.5)*scaleX, baseline);
        Position EndPoint((i+0.5)*scaleX, baseline - A[i]*scaleY - intercept);
        Display[i] = new RaySegment (W, StartPoint, EndPoint, Red, barWidth);
        Display[i]->Draw();
        }
    DelayMS(2000);

    //get the starting time of the sort
    struct timeb timeStart;
    ftime(&timeStart);

    switch (whichSort)
        {
        case terrible:
            SortWorst(W, Display, A, toSort, load);
            break;
        case bubble:
            BubbleSort(W, Display, A, toSort, load);
            break;
        case bidibubble:
            TwoWayBubbleSort(W, Display, A, toSort, load);
            break;
        case shell:
            ShellSort(W, Display, A, toSort, load);
            break;
        case selection:
            SelectionSort(W, Display, A, toSort, load);
            break;
        case insertion:
            InsertionSort(W, Display, A, toSort, load);
            break;
        case quick:
            QuickSort(W, Display, A, 0, toSort-1, load);
        }

    //get the end time of the sort
    struct timeb timeEnd;
    ftime(&timeEnd);

    //redisplay the array in "finished" colors
    for (i = 0; i < count; i++)
        {
        Display[i]->Erase();
        Display[i]->SetColor(Green);
        Display[i]->Draw();
        }

    //calculate and format the elapsed time for display in the window
    double Elapsed = (timeEnd.time + timeEnd.millitm/1000.) -
                     (timeStart.time + timeStart.millitm/1000.);
    int sig = log10(Elapsed) + 4;
    char cszElapsed[25];
    gcvt(Elapsed, sig, cszElapsed);
    string Status = "Elapsed Time: " + (string)cszElapsed + " seconds";

    RefreshDisplay(W, Status, Blue);

    Pause();
    W.Close();
    }

/*********************************************************************************************/

void Pause()
    {
    char temp;
    cout << "Type a character and [Enter] to continue: ";
    cin >> temp;
    }