 #ifndef CIMAGE_CLASS
 #define CIMAGE_CLASS
 #define FOREGROUND_COLOR M_RGB888(0,255,0)
 
 #include "cmatrix"
 #include <ctype.h>
 #include <fstream.h>
 //#include <mil.h>
 #include <stdlib.h>
 #include "CPixel"
 #define PPM 6
 
 #define PGM 5
 
 #define ASCIIPPM 3
 
 #define ASCIIPGM 2
 
 #define BINARYPPM 6
 
 #define BINARYPGM 5
 class ColorImage : public CMatrix< CPixel<T> >
 {
 public:
         ColorImage();
         ColorImage(int x, int y);
         ColorImage(char * filename);
         void Read(const char * filename); //Reads in a ppm or pgm  It figures out the type based upon the magic number.
         void Write(const char * filename,int magicnumber=PPM); //Writes an image based upon its magic number; 
                 
 };

class GreyImage : public CMatrix<T>
 {
 public:
         GreyImage();
         GreyImage(int x, int y);
         GreyImage(char * filename);
         ~GreyImage();
 //IO Operations:
         void Read(char * filename); //Reads in a ppm or pgm  It figures out the type based upon the magic number.
         void Write(char * filename,int magicnumber); //Writes an image based upon its magic number; 
 };


 template <typename T>
 GreyImage<T>::GreyImage()
 {
         CMatrix<T>();
 }
 
 template <typename T>
 GreyImage<T>::GreyImage(int x, int y)
 {
         CMatrix<T>(x, y);
 }
 
 template <typename T>
 GreyImage<T>::GreyImage(char * filename)
 {
         Read(filename);
 }                                               
 template<typename T>
 void GreyImage<T>::Read(char * filename)
 {
 
         ifstream fin( filename, ios::in | ios::binary | ios::nocreate );
         if( fin.fail() )
         {  
                 cerr << "Fail to open input file " << filename << " in ppm::read()" << endl;
                 exit( -4272 );
         }
 
     char magicNumber[2],comment[81];
         int MN,xmax,ymax,image_max;             
         unsigned int x,y,z,i;
     unsigned char * tempbuffer;
     fin.getline( magicNumber, 10);
         MN=atoi(magicNumber+1);
     while( fin.peek() == '#' )  fin.getline( comment, 81 );  //remove comments
         while( !isdigit( (int)fin.peek() ) )
                 fin.get(magicNumber[1]);
     fin >> xmax >> ymax >> image_max;
         if((unsigned)xmax!=TotX || (unsigned)ymax!=TotY)
                 SetSize(xmax,ymax);
         while(fin.peek()!='\n') fin.get();
         fin.get(); //remove extra newline
 
     switch( MN){
         case 3: //ASCII PPM
                 for (i=0; i<size(); i++ )
                 {
                         fin >> x >> y >> z; 
                         m_CMatrix[i] = (T)(x+y+z)/3.0;
                 };
                 break;
     case 6: //BINARY PPM
                 tempbuffer = new unsigned char[size()*3];
                 fin.read(tempbuffer, size()*3);
         for (i=0; i<size(); i++ )
                 {   
                         m_CMatrix[i]=(tempbuffer[i*3]+ tempbuffer[i*3+1]+ tempbuffer[i*3+2])/3;  
                 }
                 delete [] tempbuffer; 
                 break;
         case 2: //ASCII PGM
                 int input;
                 for (i=0; i<size(); i++)
                 {
                         fin >> input;
                         m_CMatrix[i] = input;
                 }
                 break;
         case 5: //BINARY PGM
                 tempbuffer = new unsigned char[size()];
                 fin.read(tempbuffer, size());
                 for(i=0; i<size(); i++)
                         m_CMatrix[i]=tempbuffer[i];
                 break;
 //functionality not added for the pbm class.  Maybe later.  Its just not important.
         fin.close();
         }
 }
 
 template <typename T>
 void GreyImage<T>::Write(char *filename, int magicnumber)
 {
         int i,j;
         assert(size()>0);
         fstream fout( filename, ios::out | ios::binary );
         if( fout.fail() )
         {
                 cerr << "Error opening output file ColorImage::Write()" << endl;
                 cerr << "exit w/ error code -1345" << endl;
                 exit( -1345 );
         }
         fout << "P" << magicnumber << endl << x() << ' ' << y() << endl << 255 << endl;
         switch(magicnumber)
         {
         case 3: //ASCII PPM
                 for(i=0; i<size(); i++ )
                         fout << (int)m_CMatrix[i] << ' ' << (int)m_CMatrix[i] << ' ' << (int)m_CMatrix[i] << ' ';
                 break;
         case 6: //BINARY PPM
                 char* tempbuffer;
                 tempbuffer = new char[size()*3];
                         for(i=0; i<size(); i++)
                                 for(j=0; j<size(); j++)
                                         tempbuffer[i*3+j]=m_CMatrix[i];
                 fout.write(tempbuffer,(size()*3));
                 break;
         case 2: //ASCII PGM
                 for(i=0; i<size(); i++)
                         fout << m_CMatrix[i] << ' ';
                 break;
         case 5: //BINARY PGM
                 tempbuffer = new char[size()];
                 for(i=0; i<size(); i++)
                         tempbuffer[i]=m_CMatrix[i];
                 fout.write(tempbuffer, size());
                 break;
         }
 }
 template<typename T>
 ColorImage<T>::ColorImage()
 {
         CMatrix<CPixel<T> >();
 }
 
 
 template<typename T>
 ColorImage<T>::ColorImage(int x, int y)
 {
         CMatrix<CPixel<T> >(x, y);
 }
 
 template<typename T>
 ColorImage<T>::ColorImage(char *filename)
 {
         Read(filename);
 }
 template<typename T>
 void ColorImage<T>::Read(const char * filename)
 {
         fstream fin( filename, ios::in | ios::binary | ios::nocreate );
         if( fin.fail() )
         {  
                 cerr << "Fail to open input file " << filename << " in ColorImage::read()" << endl;
                 exit( -4272 );
         }
 
     char magicNumber[2],comment[81];
         int MN,xmax,ymax,image_max;
     
     fin.getline( magicNumber, 10);
         MN=atoi(magicNumber[1]);
     while( fin.peek() == '#' )  fin.getline( comment, 81 );  //remove comments
         while( !isdigit( (int)fin.peek() ) )
                 fin.get(magicNumber[1]);
     fin >> xmax >> ymax >> image_max;
         if(xmax!=TotX || ymax!=TotY)
                 SetSize(xmax,ymax);
         while(fin.peek()!='\n') fin.get();
         fin.get(); //remove extra newline
     unsigned char * tempbuffer;
     switch( MN)
         case 3: //ASCII PPM
                 int x,y,z;
                 for ( unsigned int i=0; i<size(); i++ )
                 {
                         fin >> x >> y >> z; 
                         m_CMatrix[i].x=x;
                         m_CMatrix[i].y=y;
                         m_CMatrix[i].z=z;
             }
                 break;
     case 6: //BINARY PPM
                 tempbuffer = new unsigned char[size()*3];
                 fin.read(tempbuffer, size()*3);
         for ( long i=0; i<size; i++ )
                 {   
                         m_CMatrix[i]=CPixel<unsigned char>(tempbuffer[i*3], tempbuffer[i*3+1], tempbuffer[i*3+2]);  
                 }
                 delete [] tempbuffer; 
                 break;
         case 2: //ASCII PGM
                 int input;
                 for ( unsigned int i=0; i<size(); i++)
                 {
                         fin >> input;
                         image_data[i] = (unsigned char)input;
                 }
                 break;
         case 5: //BINARY PGM
                 tempbuffer = new unsigned char[size()];
                 fin.read(tempbuffer, size());
                 for( long i=0; i<size(); i++)
                         m_CMatrix[i]=tempbuffer[i];
                 break;
 //functionality not added for the pbm class.  Maybe later.  Its just not important.
         fin.close();
 }
 
 
 template<typename T>
 void ColorImage<T>::Write(const char * filename, int magicnumber)
 {
         int i;
         assert(size()>0);
         fstream fout( filename, ios::out | ios::binary );
         if( fout.fail() )
         {
                 cerr << "Error opening output file ColorImage::Write()" << endl;
                 cerr << "exit w/ error code -1345" << endl;
                 exit( -1345 );
         }
         fout << "P" << magicnumber << endl << x() << ' ' << y() << endl << 255 << endl;
         switch(magicnumber)
         {
         case 3: //ASCII PPM
                 for(i=0; i<size(); i++ )
                         fout << int(m_CMatrix[i].x) << ' ' << int(m_CMatrix[i].y) 
                                  << ' ' << int(m_CMatrix[i].z) <<' ';
                 break;
         case 6: //BINARY PPM
                 char* tempbuffer;
                 tempbuffer = new char[size()*3];
                 for(i=0; i<size(); i++)
                 {
                         tempbuffer[i*3]=m_CMatrix[i].x;
                         tempbuffer[i*3+1]=m_CMatrix[i].y; 
                         tempbuffer[i*3+2]=m_CMatrix[i].z;
                 }
                 fout.write(tempbuffer,(size()*3));
                 break;
         case 2: //ASCII PGM
                 for(i=0; i<size(); i++)
                         fout << m_CMatrix[i].intensity() << ' ';
                 break;
         case 5: //BINARY PGM
                 tempbuffer = new char[size()];
                 for(i=0; i<size(); i++)
                         tempbuffer[i]=m_CMatrix[i].intensity();
                 fout.write(tempbuffer, size());
                 break;
         }
 }
