//
//  matfp.cpp
//  fp
//
//  Created by Robert Delaney on 2/1/17.
//
//

#include "matfp.hpp"
#include "matfpConv.hpp"
#include "matfpMath.hpp"

long myDecPrec=16;

// Constructor
matfp::matfp()
{
    /*
    nr = 1;
    nc = 1;
    array = (fp**)malloc(nr*sizeof(fp*));
    array[0] = (fp*)malloc(nc*sizeof(fp));
    array[0][0] = 0.;
     */
    nr = 0;
    nc = 0;
    array = NULL;
}

// destructor
matfp::~matfp()
{
    INT32		i;
    
    if(array)
    {
        for(i=0;i<nr;i++)
            if(array[i])
            {   /*
                for(j=0;j<nc;j++)
                {
                    if(array[i][j].i.nn && array[i][j].i.b)
                        free(array[i][j].i.b);
                }
                 */
                free(array[i]);
            }
        free(array);
    }
}

matfp::matfp(const char *inString)
{
    //matfp		z;
    //INT32		i, j;
    
    nr = 0;
    nc = 0;
    array = NULL;
    
    if(!matfpConvFromStr(*this, inString))
        exit(1);
    /*
    nr = z.nr;
    nc = z.nc;
    
    array = (fp**)malloc(nr*sizeof(fp*));
    for(i=0;i<nr;i++)
        array[i] = (fp*)malloc(nc*sizeof(fp));
    
    for(i=0;i<nr;i++)
        for(j=0;j<nc;j++)
            array[i][j] = z.array[i][j];
     */
}

matfp& matfp::operator= (const matfp& x)
{
    INT32	i, j;
    
    if(this==&x)
        return *this;
    
    if(!x.array)
    {
        return *this;
    }
    
    nr = x.nr;
    nc = x.nc;
    
    array = (fp**)malloc(nr*sizeof(fp*));
    for(i=0;i<nr;i++)
        array[i] = (fp*)malloc(nc*sizeof(fp));
    
    for(i=0;i<nr;i++)
        for(j=0;j<nc;j++)
            init(array[i][j]);
    
    for(i=0;i<nr;i++)
        for(j=0;j<nc;j++)
            array[i][j] = x.array[i][j];
    
    return *this;
}

matfp matfp::operator- ()
{
    matfp		z;
    INT32		i, j;
    
    z = *this;
    for(i=0;i<z.nr;i++)
        for(j=0;j<z.nc;j++)
            z.array[i][j] = -z.array[i][j];
    
    return z;
}

matfp matfp::operator- () const
{
    matfp		z;
    INT32		i, j;
    
    z = *this;
    for(i=0;i<z.nr;i++)
        for(j=0;j<z.nc;j++)
            z.array[i][j] = -z.array[i][j];
    
    return z;
}

bool matfp::operator== (const matfp& y)
{
    INT32		i, j;
    
    if((*this).nr!=y.nr || (*this).nc!=y.nc)
        return false;
    
    for(i=0;i<y.nr;i++)
        for(j=0;j<y.nc;j++)
            if((*this).array[i][j]!=y.array[i][j])
                return false;
    
    return true;
}

bool matfp::operator!= (const matfp& y)
{
    INT32		i, j;
    
    if((*this).nr!=y.nr || (*this).nc!=y.nc)
        return true;
    
    for(i=0;i<y.nr;i++)
        for(j=0;j<y.nc;j++)
            if((*this).array[i][j]!=y.array[i][j])
                return true;
    
    return false;
}

bool matfp::operator! ()
{
    INT32		i, j;
    
    for(i=0;i<(*this).nr;i++)
        for(j=0;j<(*this).nc;j++)
            if((*this).array[i][j].i.n)
                return false;
    
    return true;
}

bool matfp::operator== (const matfp& y) const
{
    INT32		i, j;
    
    if((*this).nr!=y.nr || (*this).nc!=y.nc)
        return false;
    
    for(i=0;i<y.nr;i++)
        for(j=0;j<y.nc;j++)
            if((*this).array[i][j]!=y.array[i][j])
                return false;
    
    return true;
}

bool matfp::operator!= (const matfp& y) const
{
    INT32		i, j;
    
    if((*this).nr!=y.nr || (*this).nc!=y.nc)
        return true;
    
    for(i=0;i<y.nr;i++)
        for(j=0;j<y.nc;j++)
            if((*this).array[i][j]!=y.array[i][j])
                return true;
    
    return false;
}

bool matfp::operator! () const
{
    INT32		i, j;
    
    for(i=0;i<(*this).nr;i++)
        for(j=0;j<(*this).nc;j++)
            if((*this).array[i][j].i.n)
                return false;
    
    return true;
}

matfp matfp::operator+ (const matfp& y)
{
    matfp		z;
    
    add(z, *this, y);
    
    return z;
}

matfp matfp::operator- (const matfp& y)
{
    matfp		z;
    
    sub(z, *this, y);
    
    return z;
}


matfp matfp::operator* (const matfp& y)
{
    matfp		z;
    
    mul(z, *this, y);
    
    return z;
}

matfp matfp::operator+ (const matfp& y) const
{
    matfp		z;
    
    add(z, *this, y);
    
    return z;
}

matfp matfp::operator- (const matfp& y) const
{
    matfp		z;
    
    sub(z, *this, y);
    
    return z;
}


matfp matfp::operator* (const matfp& y) const
{
    matfp		z;
    
    mul(z, *this, y);
    
    return z;
}

matfp matfp::operator* (const fp& y)
{
    matfp		z;
    
    mul(z, *this, y);
    
    return z;
}

matfp matfp::operator* (const fp& y) const
{
    matfp		z;
    
    mul(z, *this, y);
    
    return z;
}

matfp matfp::operator* (const mb& y)
{
    matfp		z;
    
    mul(z, *this, y);
    
    return z;
}

matfp matfp::operator* (const mb& y) const
{
    matfp		z;
    
    mul(z, *this, y);
    
    return z;
}

matfp matfp::operator* (double y)
{
    matfp		z;
    
    mul(z, *this, y);
    
    return z;
}
/*
matfp matfp::operator* (double y) const
{
    matfp		z;
    
    mul(z, *this, y);
    
    return z;
}
 */

matfp matfp::operator/ (const fp& y)
{
    matfp		z;
    
    div(z, *this, y);
    
    return z;
}

matfp matfp::operator/ (const fp& y) const
{
    matfp		z;
    
    div(z, *this, y);
    
    return z;
}

matfp matfp::operator/ (const mb& y)
{
    matfp		z;
    
    div(z, *this, y);
    
    return z;
}

matfp matfp::operator/ (const mb& y) const
{
    matfp		z;
    
    div(z, *this, y);
    
    return z;
}

matfp matfp::operator/ (double y)
{
    matfp		z;
    
    div(z, *this, y);
    
    return z;
}
/*
matfp matfp::operator/ (const double& y) const
{
    matfp		z;
    
    div(z, *this, y);
    
    return z;
}
*/
ostream& operator <<(ostream &s, const matfp& x)
{
    char	*xString;
    
    matfpConvToStr(xString, x);
    s << xString;
    
    free(xString);
    
    return s;
}


istream& operator >>(istream &s, matfp& x)
{
    char	xStr[10000]; // increase if needed
    
    s.width(10000); // increase if needed
    
    s >> xStr;
    
    if(!matfpConvFromStr(x, xStr))
        cerr << "conversion error!" << endl;
    
    return s;
}

matfp operator* (const fp& x, const matfp& y)
{
    matfp		z;
    
    mul(z, y, x);
    
    return z;
}

matfp operator* (const mb& x, const matfp& y)
{
    matfp		z;
    
    mul(z, y, x);
    
    return z;
}

matfp operator* (double x, const matfp& y)
{
    matfp		z;
    
    mul(z, y, x);
    
    return z;
}


