///
///  Copyright (C) 2004-2007 Andrej Vodopivec <andrejv@users.sourceforge.net>
///
///  This program is free software; you can redistribute it and/or modify
///  it under the terms of the GNU General Public License as published by
///  the Free Software Foundation; either version 2 of the License, or
///  (at your option) any later version.
///
///  This program is distributed in the hope that it will be useful,
///  but WITHOUT ANY WARRANTY; without even the implied warranty of
///  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
///  GNU General Public License for more details.
///
///
///  You should have received a copy of the GNU General Public License
///  along with this program; if not, write to the Free Software
///  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
///

#include "MatrCell.h"

MatrCell::MatrCell() : MathCell()
{
  m_matWidth = 0;
  m_matHeight = 0;
  m_specialMatrix = false;
}

MatrCell::~MatrCell()
{
  for (unsigned int i = 0; i < m_cells.size(); i++)
  {
    if (m_cells[i] != NULL)
      delete m_cells[i];
  }
  if (m_next != NULL)
    delete m_next;
}

MathCell* MatrCell::Copy(bool all)
{
  MatrCell *tmp = new MatrCell;
  CopyData(this, tmp);
  tmp->m_matWidth = m_matWidth;
  tmp->m_matHeight = m_matHeight;
  for (int i = 0; i < m_matWidth*m_matHeight; i++)
    (tmp->m_cells).push_back(m_cells[i]->Copy(true));
  if (all && m_next != NULL)
    tmp->AppendCell(m_next->Copy(all));
  return tmp;
}

void MatrCell::Destroy()
{
  for (unsigned int i = 0; i < m_cells.size(); i++)
  {
    if (m_cells[i] != NULL)
      delete m_cells[i];
    m_cells[i] = NULL;
  }
  m_next = NULL;
}

void MatrCell::RecalculateWidths(CellParser& parser, int fontsize, bool all)
{
  double scale = parser.GetScale();
  for (int i = 0; i < m_matWidth*m_matHeight; i++)
  {
    m_cells[i]->RecalculateWidths(parser, MAX(8, fontsize - 2), true);
  }
  for (int i = 0; i < m_matWidth; i++)
  {
    m_widths.push_back(0);
    for (int j = 0; j < m_matHeight; j++)
    {
      m_widths[i] = MAX(m_widths[i], m_cells[m_matWidth * j + i]->GetFullWidth(scale));
    }
  }
  m_width = 0;
  for (int i = 0; i < m_matWidth; i++)
  {
    m_width += (m_widths[i] + SCALE_PX(10, scale));
  }
  if (m_width < SCALE_PX(14, scale))
    m_width = SCALE_PX(14, scale);
  MathCell::RecalculateWidths(parser, fontsize, all);
}

void MatrCell::RecalculateSize(CellParser& parser, int fontsize, bool all)
{
  double scale = parser.GetScale();

  for (int i = 0; i < m_matWidth*m_matHeight; i++)
  {
    m_cells[i]->RecalculateSize(parser, MAX(8, fontsize - 2), true);
  }
  for (int i = 0; i < m_matHeight; i++)
  {
    m_centers.push_back(0);
    m_drops.push_back(0);
    for (int j = 0; j < m_matWidth; j++)
    {
      m_centers[i] = MAX(m_centers[i], m_cells[m_matWidth * i + j]->GetMaxCenter());
      m_drops[i] = MAX(m_drops[i], m_cells[m_matWidth * i + j]->GetMaxDrop());
    }
  }
  m_height = 0;
  for (int i = 0; i < m_matHeight; i++)
  {
    m_height += (m_centers[i] + m_drops[i] + SCALE_PX(10, scale));
  }
  if (m_height == 0)
    m_height = fontsize + SCALE_PX(10, scale);
  m_center = m_height / 2;
  MathCell::RecalculateSize(parser, fontsize, all);
}

void MatrCell::Draw(CellParser& parser, wxPoint point, int fontsize, bool all)
{
  if (DrawThisCell(parser, point))
  {
    wxDC& dc = parser.GetDC();
    double scale = parser.GetScale();
    wxPoint mp;
    mp.x = point.x + SCALE_PX(5, scale);
    mp.y = point.y - m_center;
    for (int i = 0; i < m_matWidth; i++)
    {
      mp.y = point.y - m_center + SCALE_PX(5, scale);
      for (int j = 0; j < m_matHeight; j++)
      {
        mp.y += m_centers[j];
        wxPoint mp1(mp);
        mp1.x = mp.x + (m_widths[i] - m_cells[j * m_matWidth + i]->GetFullWidth(scale)) / 2;
        m_cells[j*m_matWidth + i]->Draw(parser, mp1, MAX(8, fontsize - 2), true);
        mp.y += (m_drops[j] + SCALE_PX(10, scale));
      }
      mp.x += (m_widths[i] + SCALE_PX(10, scale));
    }
    SetPen(parser);
    if (m_specialMatrix)
      dc.DrawLine(point.x + SCALE_PX(1, scale),
                  point.y - m_center + SCALE_PX(2, scale),
                  point.x + SCALE_PX(1, scale),
                  point.y + m_center - SCALE_PX(2, scale));
    else
    {
      // left bracket
      dc.DrawLine(point.x + SCALE_PX(5, scale),
                  point.y - m_center + SCALE_PX(2, scale),
                  point.x + SCALE_PX(1, scale),
                  point.y - m_center + SCALE_PX(2, scale));
      dc.DrawLine(point.x + SCALE_PX(1, scale),
                  point.y - m_center + SCALE_PX(2, scale),
                  point.x + SCALE_PX(1, scale),
                  point.y + m_center - SCALE_PX(2, scale));
      dc.DrawLine(point.x + SCALE_PX(1, scale),
                  point.y + m_center - SCALE_PX(2, scale),
                  point.x + SCALE_PX(5, scale),
                  point.y + m_center - SCALE_PX(2, scale));
      // right bracket
      dc.DrawLine(point.x + m_width - SCALE_PX(5, scale) - 1,
                  point.y - m_center + SCALE_PX(2, scale),
                  point.x + m_width - SCALE_PX(1, scale) - 1,
                  point.y - m_center + SCALE_PX(2, scale));
      dc.DrawLine(point.x + m_width - SCALE_PX(1, scale) - 1,
                  point.y - m_center + SCALE_PX(2, scale),
                  point.x + m_width - SCALE_PX(1, scale) - 1,
                  point.y + m_center - SCALE_PX(2, scale));
      dc.DrawLine(point.x + m_width - SCALE_PX(1, scale) - 1,
                  point.y + m_center - SCALE_PX(2, scale),
                  point.x + m_width - SCALE_PX(5, scale) - 1,
                  point.y + m_center - SCALE_PX(2, scale));
    }
    UnsetPen(parser);
  }
  MathCell::Draw(parser, point, fontsize, all);
}

wxString MatrCell::ToString(bool all)
{
  wxString s = wxT("matrix(");
  for (int i = 0; i < m_matHeight; i++)
  {
    s += wxT("[");
    for (int j = 0; j < m_matWidth; j++)
    {
      s += m_cells[i * m_matWidth + j]->ToString(true);
      if (j < m_matWidth - 1)
        s += wxT(",");
    }
    s += wxT("]");
    if (i < m_matHeight - 1)
      s += wxT(",");
  }
  s += wxT(")");
  s += MathCell::ToString(all);
  return s;
}

wxString MatrCell::ToTeX(bool all)
{
  wxString s = wxT("\\pmatrix{");
  for (int i = 0; i < m_matHeight; i++)
  {
    for (int j = 0; j < m_matWidth; j++)
    {
      s += m_cells[i * m_matWidth + j]->ToTeX(true);
      if (j < m_matWidth - 1)
        s += wxT(" & ");
    }
    if (i < m_matHeight - 1)
      s += wxT("\\cr ");
  }
  s += wxT("}");
  s += MathCell::ToTeX(all);
  return s;
}

void MatrCell::SetDimension()
{
  if (m_matHeight != 0)
    m_matWidth = m_matWidth / m_matHeight;
}

void MatrCell::SelectInner(wxRect& rect, MathCell** first, MathCell** last)
{
  *first = NULL;
  *last = NULL;
  for (int i = 0; i < m_matHeight; i++)
  {
    for (int j = 0; j < m_matWidth; j++)
    {
      if (m_cells[i*m_matWidth + j]->ContainsRect(rect))
        m_cells[i*m_matWidth + j]->SelectRect(rect, first, last);
    }
  }
  if (*first == NULL || *last == NULL)
  {
    *first = this;
    *last = this;
  }
}


syntax highlighted by Code2HTML, v. 0.9.1