#include "matrix.h"
#include <iostream.h>

Matrix::Matrix(unsigned int row, unsigned int col, double value, int fill)
  {
  if ((row > 0) && (col > 0))
    {
    this->row=row;
    this->col=col;
    }
    else
      {
      this->row=0;
      this->col=0;
      }
  if ((row > 0) && (col > 0))
    {
    matrix=new double*[row];
    for (unsigned int i=0; i < row; i++)
      matrix[i]=new double[col];

    if (fill == 0) //--- fill==0 -> macierz wypelniona value
      {
      for (unsigned int i=0; i < row; i++)
        for (unsigned int j=0; j < col; j++)
          matrix[i][j]=value;
      }
      else
        if (fill == 1) //--- fill==1 -> macierz diagonalna wypelniona value
          {
          for (unsigned int i=0; i < row; i++)
            for (unsigned int j=0; j < col; j++)
              if (i == j)
                matrix[i][j]=value;
                else
                  matrix[i][j]=0;
          }
          //--- else macierz nie jest wypelniana
    }
    else
      {
      matrix=0;
      }
  }

Matrix::~Matrix()
  {
  if ((row > 0) && (col > 0))
    {
    for (unsigned int i=0; i < row; i++)
      delete [] matrix[i];
    delete [] matrix;
    }
  }

Matrix::Matrix(const Matrix & m)
  {
  row=0;
  col=0;
  matrix=0;
  *this=m;
  }

Matrix & Matrix::operator=(const Matrix & m)
  {
  if ((m.row > 0) && (m.col > 0))
    {
    if ((m.row != this->row) || (m.col != this->col))
      {
      if ((this->row > 0) && (this->col > 0))
        {
        for (unsigned int i=0; i < this->row; i++)
          delete [] matrix[i];
        delete [] matrix;
        }

      this->row=m.row;
      this->col=m.col;

      matrix=new double*[this->row];
      for (unsigned int i=0; i < this->row; i++)
        matrix[i]=new double[this->col];

      }

    for (unsigned int i=0; i < this->row; i++)
      for (unsigned int j=0; j < this->col; j++)
        matrix[i][j]=m.matrix[i][j];

    }
    else
      {
      if ((this->row > 0) && (this->col > 0))
        {
        for (unsigned int i=0; i < this->row; i++)
          delete [] matrix[i];
        delete [] matrix;

        this->row=0;
        this->col=0;
        matrix=0;
        }
      }

  return *this;
  }

Matrix & Matrix::Resize(unsigned int row, unsigned int col)
  {
  if ((row > 0) && (col > 0))
    {
    if ((row != this->row) || (col != this->col))
      {
      if ((this->row > 0) && (this->col > 0))
        {
        for (unsigned int i=0; i < this->row; i++)
          delete [] matrix[i];
        delete [] matrix;
        }

      this->row=row;
      this->col=col;

      matrix=new double*[this->row];
      for (unsigned int i=0; i < this->row; i++)
        matrix[i]=new double[this->col];

      }

    }
    else
      {
      if ((this->row > 0) && (this->col > 0))
        {
        for (unsigned int i=0; i < this->row; i++)
          delete [] matrix[i];
        delete [] matrix;

        this->row=0;
        this->col=0;
        matrix=0;
        }
      }

  return *this;
  }

//--- Nie kasuje calej macierzy tylko glowna tablice. Wskazniki wierszy sa przejmowane do nowej macierzy. ---//  
Matrix & Matrix::AddRow(double * vec, unsigned int n)
  {
  if ((vec!=0) && (n>0))
    {
    if ((row > 0) && (col == n))
      {
      double** tmp=new double*[row+1];
      for (unsigned int i=0; i < row; i++)
        tmp[i]=matrix[i];
      tmp[row]=new double[col];
      for (unsigned int i=0; i < col; i++)
        tmp[row][i]=vec[i];
      delete [] matrix;
      matrix=tmp;
      row++;
      tmp=0;
      }
      else
        if ((row == 0) && (col == 0))
          {
          Resize(1,n);
          for (unsigned int i=0; i < col; i++)
            matrix[0][i]=vec[i];
          }
    }
  return *this;
  }

Matrix & Matrix::AddRows(const Matrix & m)
  {
  if ((row > 0) && (col == m.ncols()))
    {
    double** tmp=new double*[row+m.nrows()];
    for (unsigned int i=0; i < row; i++)
      tmp[i]=matrix[i];
    for (unsigned int i=0; i < m.nrows(); i++)
      {
      tmp[row+i]=new double[col];
      for (unsigned int j=0; j < col; j++)
        tmp[row+i][j]=m[i][j];
      }
    delete [] matrix;
    matrix=tmp;
    row+=m.nrows();
    tmp=0;
    }
    else
      if ((row == 0) && (col == 0))
        {
        *this=m;
        }
  return *this;
  }

Matrix & Matrix::operator+=(const Matrix & m)
  {
  if ((m.row == this->row) && (m.col == this->col))
    {
    for (unsigned int i=0; i < row; i++)
      for (unsigned int j=0; j < col; j++)
        matrix[i][j]+=m.matrix[i][j];
    }
  return *this;
  }

Matrix & Matrix::operator-=(const Matrix & m)
  {
  if ((m.row == this->row) && (m.col == this->col))
    {
    for (unsigned int i=0; i < row; i++)
      for (unsigned int j=0; j < col; j++)
        matrix[i][j]-=m.matrix[i][j];
    }
  return *this;
  }

//--- Co to za bzdura!!!! ---//
Matrix & Matrix::operator*=(const Matrix & m)
  {
  if (this->col == m.row)
    {
    double *tmp;
    for (unsigned int i=0; i < this->row; i++)
      {
      tmp=new double[m.col];
      for (unsigned int j=0; j < m.col; j++)
        {
        tmp[j]=0;
        for (unsigned int k=0; k < this->col; k++)
          {
          tmp[j]+=this->matrix[i][k]*m.matrix[k][j];
          }
        }
      delete [] this->matrix[i];
      this->matrix[i]=tmp;
      }
    this->col=m.col;
    }
    else
      *this=Matrix(0,0);
  return *this;
  }

Matrix & Matrix::operator*=(double x)
  {
  for (unsigned int i=0; i < row; i++)
    for (unsigned int j=0; j < col; j++)
      matrix[i][j]*=x;

  return *this;
  }

unsigned int Matrix::nrows() const
  {
  return row;
  }
unsigned int Matrix::ncols() const
  {
  return col;
  }

void Matrix::UstawElement(unsigned int row, unsigned int col, double value)
  {
  if ((row < this->row) && (col < this->col))
    matrix[row][col]=value;
  }
double Matrix::PobierzElement(unsigned int row, unsigned int col) const
  {
  if ((row < this->row) && (col < this->col))
    return matrix[row][col];
    else
      return 0;
  }

double * Matrix::operator[](unsigned int row) const
  {
  if (row < this->row)
    return matrix[row];
    else
      return 0;
  }

double ** Matrix::pmatrix() const
  {
  return matrix;
  }

Matrix Matrix::Transpose() const
  {
  Matrix m(col,row);
  for (unsigned int i=0; i < row; i++)
    for (unsigned int j=0; j < col; j++)
      m.matrix[j][i]=matrix[i][j];

  return m;
  }

double Matrix::Trace() const
  {
  if ((col == row) && (row > 0))
    {
    double tr=0;
    for (unsigned int i=0; i < row; i++)
      tr+=matrix[i][i];
    return tr;
    }
    else
      return 0;
  }

double Matrix::ColMax(unsigned int col) const
  {
  if ((this->row != 0) && (col < this->col))
    {
    double max=matrix[0][col];
    for (unsigned int i=1; i < this->row; i++)
      max=max < matrix[i][col] ? matrix[i][col] : max;
    return max;
    }
    else
      return 0;
  }
double Matrix::ColMin(unsigned int col) const
  {
  if ((this->row != 0) && (col < this->col))
    {
    double min=matrix[0][col];
    for (unsigned int i=1; i < this->row; i++)
      min=min > matrix[i][col] ? matrix[i][col] : min;
    return min;
    }
    else
      return 0;
  }


//----------------------------------------------------------------------------//

Matrix operator+(const Matrix & m1, const Matrix & m2)
  {
  Matrix m(m1);
  return (m+=m2);
  }

Matrix operator-(const Matrix & m1, const Matrix & m2)
  {
  Matrix m(m1);
  return (m-=m2);
  }

Matrix operator*(const Matrix & m1, const Matrix & m2)
  {
  Matrix m(m1);
  return (m*=m2);
  }

Matrix operator*(const Matrix & m, double x)
  {
  Matrix m_out(m);
  return (m_out*=x);
  }

Matrix operator*(double x, const Matrix & m)
  {
  return (m*x);
  }

void WypiszM(const Matrix & m)
  {
  unsigned int row=m.nrows();
  unsigned int col=m.ncols();
  for (unsigned int i=0; i < row; i++)
    {
    for (unsigned int j=0; j < col; j++)
      {
      cout << m[i][j] << "  ";
      }
    cout << endl;
    }
  cout << endl;
  }
