#include <iostream.h>
#include <fstream.h>

enum Err
{
    Success,
    Error
};

enum ExceptionType
{
    OpenSource,
    OpenTarget,
    Read,
    Write
};

//Clasa de exceptii care contine mai multe informatii
//decat doar tipul clasei respective.
class CopyException
{
public:
        ExceptionType   Inteligence;
        CopyException(ExceptionType V) : Inteligence(V) {}
};

void Copy(char *Source, char *Target)
{
    ifstream    In(Source);
    if(!In)
        throw CopyException(OpenSource);

    ofstream    Out(Target);
    if(!Out)
        throw CopyException(OpenTarget);

    char        CTemp;
    //Cat timp nu s-a ajuns la sfarsitul fisierului
    //de intrare si nu a aparut o eroare la intrare
    //si nu a aparut o eroare la iesire ...
    while(!In.eof())
    {
        CTemp = In.get();
        if(In.good())
            Out.put(CTemp);
        else if(!In.eof())
                throw CopyException(Read);

        if(Out.fail())
                throw CopyException(Write);
    }
    //Foarte sanatos ...
    In.close();
    Out.close();
    
    cerr << "O.K." << endl;

}

//Programul are parametri in linia de comanda
int main(int argc, char *argv[])
{
    //Sunt sau nu furnizate corect argumentele ?!?
    switch(argc)
    {
        case 3:
                cerr << argv[0] << " realizeaza copia ASCII : " << argv[1] << " -> " << argv[2] << " : ";
                break;
        default :
                cerr << "Utilizare : " << argv[0] << " sursa destinatie" << endl;
                return Error;
    }

    char        *OpenError("Eroare la deschiderea fisierului ");
    char        *WriteError("Eroare la scrierea in fisierul ");
    char        *ReadError("Eroare la citirea din fisierul ");

    try
    {
        Copy(argv[1], argv[2]);
    }
    catch(CopyException ExInstance)
    {
        switch(ExInstance.Inteligence)
        {
            case OpenSource :
                cerr << OpenError << argv[1] << endl;
                return Error;
            case OpenTarget :
                cerr << OpenError << argv[2] << endl;
                return Error;
            case Read :
                cerr << ReadError << argv[1] << endl;
                return Error;
            case Write :
                cerr << WriteError << argv[2] << endl;
                return Error;
        }
        return Error;
    }
    return Success;
}
