// Dr. Ismail Toroslu
// The IntArray class implements an array object with limited capability.
// This class provides examples of the use of dynamic arrays, operator
// overloading, and the use of a destructor.

#include "iostream.h"

const int ArraySize = 24;
const int SZ = 10;

class IntArray {

   public:
   	IntArray (int sz = ArraySize);
   	IntArray (const IntArray &);
   	~IntArray();
   	IntArray & operator=(const IntArray &);
   	int & operator[](int);
   	int getSize() {return size;};
        IntArray operator+(IntArray &);
        friend ostream& operator<<(ostream & os, IntArray & ia);
        friend IntArray operator+(const IntArray &, int *);

   private:
   	int size; 
        int *ia;
    	int id;

};


// Constructor that takes in the size of the array and initializes each 
// array element to 0.
IntArray::IntArray (int sz) {  
   	
   static int number = 0;   
   number++;
   size = sz;
   id = number;
   ia = new int [size];
   for (int i=0; i< sz; ++i)
	  ia[i]=0; 
   cout << "int constructor id: " << id << endl;

}

// Copy constructor
IntArray::IntArray(const IntArray &iA) {

   size = iA.size;
   id = iA.id*(-1);
   ia = new int [size];
   for (int i=0;i<size;++i)
	  ia[i]=iA.ia[i]; 
   cout << "copy constructor id: " << id << endl;

}


IntArray::~IntArray() {

   cout << "destruct id: " << id << endl; 
   delete ia; 

};


// Overloading the = operator.
IntArray & IntArray::operator=(const IntArray &iA) {  

   delete ia;
   size = iA.size;
   ia = new int [size];
   for (int i=0;i< size;++i)
	  ia[i]=iA.ia[i];
   cout << "= overloading id: " << id << endl;

   return *this; 
}


// Overloading []...allows access to each array element.
int & IntArray::operator[](int index) {  
   return ia[index];
}

// Overloading the + operator. Concatenates two IntArrays, essentially.
IntArray IntArray::operator+(IntArray & ip)
{  IntArray ia_tmp(size+ip.size);
   for (int i=0; i< size; ++i)
	  ia_tmp.ia[i] = ia[i];
   for (int i=size; i<ia_tmp.size;i++)
	  ia_tmp.ia[i] = ip.ia[i-size];
   ia_tmp.id = id + ip.id;
   return (ia_tmp);
}

// Overloading the + operator. Adds corresponding elements.
IntArray operator+(const IntArray & ip, int a[]) {

   IntArray ia_tmp(10);
   for (int i=0; i<ip.size;i++)
	  ia_tmp.ia[i] = ip.ia[i]+a[i];
   ia_tmp.id = 2*ip.id;
   return (ia_tmp);
}

// Overloading the << operator.
ostream& operator<<(ostream & os, IntArray & ia)
{  os <<"id: " << ia.id << " size: " << ia.size <<"\n";
   for (int i=0; i< ia.size; ++i)
	  os << ia.ia[i]<<" ";
   os << "\n";
   return os;
}

main()
{
   int mySize=20;
   int ia[SZ];

   for (int i = 0; i< SZ; i++)
     ia[i] = 2*i;

   // Create a couple IntArrays, as well as a reference to an IntArray.
   IntArray myArray(mySize), iA(SZ);
   IntArray *pA=&myArray;
   IntArray iA2;

   // Calls [] overloading.
   iA[3] = 4;
   iA2[2] = iA[3];
   iA[3] = 7;
   cout<<"printing out iA2[2] " << iA2[2]<<"\n";
   cout<<"printing out iA[3] " << iA[3]<<"\n";

   {
   // Calls copy constructor.
   IntArray iA3=iA2;
   cout << "printing size of iA3 " << iA3.getSize()<<"\n";
   cout << "printing iA3[2] " << iA3[2] << endl; 

   }

   // Calls overloaded =, overloaded <<
   IntArray iA4;
   iA4 = myArray;
   cout << iA4;

   // Calls member +
   IntArray iA5 = iA+iA2;
   cout << "iA+iA2: " << iA5;

   // Calls friend +
   IntArray iA6 = iA + ia;
   cout << "iA+ia: " << iA6;

   (*pA)[2] = 5;
   cout << "printing myArray[2] " << myArray[2] << endl;
}

