#include <iostream>
#include <iomanip>
#include <limits>
#include <cmath>
using namespace std;
string generatePlaque(unsigned int rows,unsigned int columns, char background);
void applyBorder(string &plaque, char borderType);
void getPlaqueDimensions(const string &plaque, unsigned int &rows, unsigned int
                         &columns);
int getCharacterIndex(string text, unsigned int row, unsigned int column);
void insertSubstring(string &plaque, string substring,unsigned int row);
//Plaque Dimensions and Costs
const int SMALL_PLAQUE_WIDTH = 14;
const int SMALL_PLAQUE_HEIGHT = 5;
const double SMALL_PLAQUE_COST = 4.99;
const int MEDIUM_PLAQUE_WIDTH = 21;
const int MEDIUM_PLAQUE_HEIGHT = 7;
const double MEDIUM_PLAQUE_COST = 7.99;
const int LARGE_PLAQUE_WIDTH = 40;
const int LARGE_PLAQUE_HEIGHT = 16;
const double LARGE_PLAQUE_COST = 15.95;
/*
Generates a multi-line string to represent a plaque.
Parameters:
rows - the height of the plaque (number of lines)
columns - the width of the plaque (number of columns not including linefeed)
background - the character to use to fill the string
Returns a multi-line string made up of the background character
*/
string generatePlaque(unsigned int rows, unsigned int columns, char background)
{




    string plaque = "";
   for(unsigned int row = 0 ; row < rows ;row++){
        for(unsigned int col = 0 ; col <columns ;col++){
         plaque += background;
        }

     plaque+="\n";
    }


    return plaque;
}
/*
Replaces the characters along the edge of the string (top, bottom, left, and right
sides)
with the provided character.
Parameters:
&plaque - The string to modify
borderType - The character to use for the border
*/
void applyBorder(string &plaque, char borderType)
{

    unsigned int rows;
    unsigned int columns;

    getPlaqueDimensions(plaque,rows,columns);

    for(unsigned int row = 0 ; row <rows ;row++){

        for(unsigned int col = 0 ; col <columns ;col++){

            int characterIndex = getCharacterIndex(plaque,row,col);


            if(row==0 ||row==rows-1 ||col==0||col==columns-1  ){

                plaque[characterIndex] = borderType;
            }





        }

    }





    //Your code here
}
/*
Places the substring into the middle of the indicated row of the string.
Row 0 is the first line.
Parameters:
&plaque - The string to modify
substring - The new text to add.  Guaranteed to be smaller than the width of the
string.
row - The line to insert the new text. Guaranteed to be within the bounds of the
string.
*/
void insertSubstring(string &plaque, string substring, unsigned int row)
{

    unsigned int rows;
    unsigned int columns;
    int substringLength = substring.length();

    getPlaqueDimensions(plaque,rows,columns);


    int startingPosition = std::round(( columns-substringLength)/2);



    int position = 0;

    for(int col = startingPosition; col < substringLength+startingPosition;col++  ){

       int characterIndex = getCharacterIndex(plaque,row,col);

       plaque[characterIndex] = substring[position];


       position ++;

    }




    //your code here
}
//----------------------------------------------------------------
//----------------------------------------------------------------
//----------------------------------------------------------------
//----------DO NOT ALTER CODE BEYOND THIS POINT-------------------
//----------------------------------------------------------------
//----------------------------------------------------------------
//----------------------------------------------------------------


int main()
{
    string newPlaque = "";
    unsigned int rows = 0;
    unsigned int columns = 0;
    //Format double output for dollar values
    cout << fixed << setprecision(2);
    //Ask user for plaque size
    cout << "Available Plaque Sizes" << endl;
    cout << "[S] " << SMALL_PLAQUE_WIDTH << "\"";
    cout << " x " << SMALL_PLAQUE_HEIGHT << "\" ";
    cout << "$"<< SMALL_PLAQUE_COST << endl;
    cout << "[M] " << MEDIUM_PLAQUE_WIDTH << "\"";
    cout << " x " << MEDIUM_PLAQUE_HEIGHT << "\" ";
    cout << "$"<< MEDIUM_PLAQUE_COST << endl;
    cout << "[L] " << LARGE_PLAQUE_WIDTH << "\"";
    cout << " x " << LARGE_PLAQUE_HEIGHT << "\" ";
    cout << "$"<< LARGE_PLAQUE_COST << endl;
    //Validate response
    do
    {
        cout << endl << "Selection: ";
        string userResponse = "";
        getline(cin, userResponse);
        //Check that user entered only a single letter
        if(userResponse.length() != 1)
        {
            cout << "\nInvalid selection.\n";
            continue;
        }
        //Check plaque size
        switch(userResponse[0])
        {
        case 's':
        case 'S':
            rows = SMALL_PLAQUE_HEIGHT;
            columns = SMALL_PLAQUE_WIDTH;
            break;
        case 'm':
        case 'M':
            rows = MEDIUM_PLAQUE_HEIGHT;
            columns = MEDIUM_PLAQUE_WIDTH;
            break;
        case 'l':
        case 'L':
            rows = LARGE_PLAQUE_HEIGHT;
            columns = LARGE_PLAQUE_WIDTH;
            break;
        default:
            cout << "\nInvalid selection.\n";
            continue;
        }
        break;
    }
    while(true);
    //Get background character to use
    do
    {
        cout << "\nDesired Background Character: ";
        string userResponse = "";
        getline(cin, userResponse);
        //Check that user entered only a single letter
        if(userResponse.length() != 1)
        {
            cout << "\nInvalid selection.\n";
            continue;
        }
        newPlaque = generatePlaque(rows, columns, userResponse[0]);
        break;
    }
    while(true);
    //Display Plaque
    cout << endl <<  columns << " x " << rows << " Plaque" << endl;
    cout << newPlaque << endl;
    //Choose Plaque Border
    do
    {
        cout << "Would you like to add a border (Y/N): ";
        string userResponse = "";
        getline(cin, userResponse);
        //Check that user entered only a single letter
        if(userResponse.length() != 1)
        {
            cout << "\nInvalid selection.\n\n";
            continue;
        }
        switch(userResponse[0])
        {
        case 'y':
        case 'Y':
            do
            {
                cout << "Border Character: ";
                string userResponse = "";
                getline(cin, userResponse);
                //Check that user entered only a single letter
                if(userResponse.length() != 1)
                {
                    cout << "\nInvalid selection.\n\n";
                    continue;
                }
                //Adds indicated character around the edges of the string
                        applyBorder(newPlaque, userResponse[0]);
                //Show updated plaque
                cout << endl <<  columns << " x " << rows << "Plaque" << endl;
                cout << newPlaque << endl;
                break;
            }
            while(true);
            break;
        case 'n':
        case 'N':
            break;
        default:
            cout << "\nInvalid selection.\n\n";
            continue;
        }
        break;
    }
    while(true);
    //Add Engraving(s)
    bool addAnotherEngraving = true;
    do
    {
        cout << "Would you like to add an engraving (Y/N): ";
        string userResponse = "";
        getline(cin, userResponse);
        //Check that user entered only a single letter
        if(userResponse.length() != 1)
        {
            cout << "\nInvalid selection.\n\n";
            continue;
        }
        switch(userResponse[0])
        {
        case 'y':
        case 'Y':
            //Ask user for message to engrave
            do
            {
                cout << "Message to engrave: ";
                getline(cin, userResponse);
                if(userResponse.length() > columns-2)
                {
                    cout << "\nDesired engraving will not fit.\n\
n";
continue;
                }
                break;
            }
            while(true);
            //Choose row for engraving
            do
            {
                cout << "Add engraving to which line? (1 - " << rows-
                        2 << "): ";
                unsigned int selectedRow = 0;
                cin >> selectedRow;
                if(cin.fail() || selectedRow < 1 || selectedRow >
                        rows-2)
                {
                    cin.clear();
                    cin.ignore(numeric_limits<streamsize>::max(),
                               '\n');
                    cout << "\nInvalid row selected.\n\n";
                    continue;
                }
                //Clears any remaining buffered input
                cin.ignore(numeric_limits<streamsize>::max(), '\n');
                //Adds the new text to the string
                insertSubstring(newPlaque, userResponse,
                                selectedRow);
                break;
            }
            while(true);
            //Display updated plaque
            cout << endl << columns << " x " << rows << " Plaque" <<
                    endl;
            cout << newPlaque << endl;
            break;
        case 'n':
        case 'N':
            addAnotherEngraving = false;
            break;
        default:
            cout << "\nInvalid selection.\n\n";
            continue;
        }
    }
    while(addAnotherEngraving == true);
    return 0;
}
/*
Determines the dimensions of the given string and
set the number of rows and columns.
Assumes each line is of equal size.
Parameters:
plaque - String containing multiple lines of text
rows - The number of lines in the string
columns - The number of characters in the longest line
(not including the linefeed)
*/
void getPlaqueDimensions
(
        const string &plaque,
        unsigned int &rows,
        unsigned int &columns
        )
{
    rows = 0;
    columns = 0;
    for(unsigned int i=0; i<plaque.length(); i++)
    {
        if(plaque[i] == '\n')
        {
            rows++;
        }
        else if(rows < 1)
        {
            columns++;
        }
    }
}
/*
Determines the index of the character at the given line and column
Parameters:
text - String containing multiple lines of text
row - The line of the desired index
column - The column of the desired index
Returns the index of the indicated position or
-1 if the column/row is outside of the string
*/
int getCharacterIndex(string text, unsigned int row, unsigned int column)
{
    unsigned int index = 0;
    //Skip characters until the desired line is found
    unsigned int rowsSeen = 0;
    while(rowsSeen < row && index < text.length())
    {
        if(text[index] == '\n')
        {
            rowsSeen++;
        }
        index++;
    }
    //Check for out of bounds index
    if(index + column >= text.length())
    {
        return -1;
    }
    return index + column;
}
