/*----
  signature: main: void -> int
  purpose: to try out our ColorPlay derived class

  compile using: (all on one line)
      g++ ColorPoint-play.cpp Point.cpp ColorPoint.cpp
          -o ColorPoint-play
  run using:
      ./ColorPoint-play | more # to better look over the results 8-)

  by: Sharon Tuttle
  last modified: 2022-11-15 - adding some more in-class examples
                              for W13-1
                 2022-11-11 - cleaned up after class
                 2022-11-10 - created 1st version during
                              class, W12-2
----*/

#include <cstdlib>
#include <iostream>
#include <string>
#include <cmath>
#include "Point.h"
#include "ColorPoint.h"
using namespace std;

int main()
{
    cout << boolalpha;

    ColorPoint c_point1;
    ColorPoint c_point2(3, 4.7, "blue");

    cout << endl;
    cout << "trying out display, no-argument version: "
         << endl;
    c_point1.display();
    c_point2.display();

    // look! I inherited accessors!

    cout << endl;
    cout << "NOTE: these inherited accessors work!: " << endl;
    cout << "    c_point1's x: " << c_point1.get_x() << endl;
    cout << "    c_point1's y: " << c_point1.get_y() << endl;    

    // and ColorPoint also has get_color

    cout << endl;
    cout << "and so does its specific-to-ColorPoint accessor:"
         << endl;
    cout << "    c_point1's color: " << c_point1.get_color()
         << endl;    

    cout << endl;
    cout << "c_point2's x: " << c_point2.get_x() << endl;
    cout << "c_point2's y: " << c_point2.get_y() << endl;    
    cout << "c_point2's color: " << c_point2.get_color()
         << endl;    

    // look! I inherited mutators, too!

    cout << endl;
    cout << "NOTE: these inherited mutators work!: " << endl;
    
    c_point1.set_x(1000);
    cout << "    c_point1's x is NOW: " << c_point1.get_x() << endl;

    c_point1.set_y(2000);
    cout << "    c_point1's y is NOW: " << c_point1.get_y() << endl;

    // and here's a new-to-ColorPoint mutator:

    cout << endl;
    cout << "and so does its specific-to-ColorPoint mutator:"
         << endl;
    c_point1.set_color("red");

    cout << "    c_point1's color is NOW: "
         << c_point1.get_color() << endl;

    // does ColorPoint inherit dist_from?

    cout << endl;
    cout << "inherited dist_from: " << endl
         << "    distance from c_point1 to c_point2: "
         << c_point1.dist_from(c_point2) << endl;

    // what about the redefined display and to_string
    //     methods?

    cout << endl;
    cout << "result of display (no arg version) for c_point1:"
         << endl;
    c_point1.display();

    cout << endl;
    cout << "result of to_string for c_point1:"
         << endl << c_point1.to_string() << endl;

    // how about the overloaded display, with 1 argument?

    cout << endl;
    cout << "result of display (ONE arg version) for c_point1:"
         << endl;
    c_point1.display("Aidan");

    // how about ==?

    ColorPoint cp3(10, 20, "purple");
    ColorPoint cp4(10, 20, "green");
    ColorPoint cp5(10, 20, "green");
    Point p1(10, 20);

    cout << endl;
    cout << "cp3: " << cp3.to_string() << endl;
    cout << "cp4: " << cp4.to_string() << endl;
    cout << "cp5: " << cp5.to_string() << endl;
    cout << "p1:  " << p1.to_string() << endl;    

    cout << endl;
    cout << "result of cp3==cp4: " << (cp3 == cp4) << endl;
    cout << "result of cp4==cp5: " << (cp4 == cp5) << endl;
    cout << "result of p1==cp5 : " << (p1 == cp5) << endl;

    // cannot do this!
    // cout << "result of cp5==p1 : " << (cp5 == p1) << endl;

    // demo of calling base class' version of a method

    ColorPoint invis_pt(13, 15, "invisible");

    cout << endl;
    cout << "calling ColorPoint version of to_string:" << endl;
    cout << invis_pt.to_string() << endl;

    cout << endl;
    cout << "calling Point version of to_string for the"
         << endl << "    same ColorPoint object:" << endl;    
    cout << invis_pt.Point::to_string() << endl;

    // demo calling Point's version of == for two ColorPoint
    //    objects

    cout << endl;

    cout << "Does this work?\n"
         << "trying: cp3.Point::operator==(cp4) :\n"
         << (cp3.Point::operator==(cp4)) << endl;

    cout << endl;

    cout << "Should be able to use a ColorPoint as an "
         << endl
         << "    argument to Point's dist_from method,"
         << endl
         << "    because it is also considered to be type Point:"
         << endl;

    cout << "trying p1.dist_from(c_point1): "
         << p1.dist_from(c_point1) << endl;

    // yes, you can have an array of type Point
    //    and put ColorPoint as well as Point objects
    //    into it (because a ColorPoint is also of type Point)

    cout << endl;
    Point my_quad[4];

    Point p_1(1, 1);
    Point p_2(2, 2);
    ColorPoint cp_1(3, 3, "green");
    ColorPoint cp_2(4, 4, "blue");

    my_quad[0] = p_1;
    my_quad[1] = p_2;
    my_quad[2] = cp_1;
    my_quad[3] = cp_2;

    cout << "Are you surprised by how the ColorPoint and"
         << endl << "   Point objects appear here?" << endl;
    
    for (int i=0; i < 4; i++)
    {
        cout << "my_quad[" << i << "]: "
             << my_quad[i].to_string() << endl;
    }
    
    cout << endl;
    return EXIT_SUCCESS;
}