/** @file
    @author Christian Engwer
    @brief Implementation of gnuplot output for 1D and 2D grids
*/

#include "../gnuplot.hh"

namespace Dune {

  /** \brief Write Gnuplot file to disk 
      \param filename Name of the file to write to
  */
  template<class GridView>
  void
  GnuplotWriter<GridView>::write(const std::string& filename) const
  {
    // open file
    std::ofstream file(filename.c_str());
    // write all column names
    file << "# coord\t";
    for (size_t i=0; i<_names.size(); i++)
      file << _names[i] << "\t";
    file << "\n";

    if (dimworld==1) {
#if !NDEBUG
        int counter = 0;
#endif
        typedef typename GridView::template Codim<0>::Iterator CellIterator;
        CellIterator it = _gv.template begin<0>();
        CellIterator end = _gv.template end<0>();
        for (; it != end; ++it)
            {
                int i = _is.index(*it);
                // check that the elements are numbered consecutively
                assert (i == counter++);
                // calc positions
                assert(it->geometry().corners() == 2);
                const FieldVector<ctype,dimworld>& left = it->geometry().corner(0);
                const FieldVector<ctype,dimworld>& right = it->geometry().corner(1);
                assert(left[0] < right[0]);
                // write gnuplot rows for left & right vertex
                writeRow(file, left, _data[2*i]);
                writeRow(file, right, _data[2*i+1]);
            }

    } else {

        typedef typename GridView::template Codim<dimworld>::Iterator VertexIterator;
        VertexIterator it  = _gv.template begin<dimworld>();
        VertexIterator end = _gv.template end<dimworld>();
        for (; it != end; ++it) {

                // write gnuplot rows for vertex
                writeRow(file, it->geometry().corner(0), _data[_is.index(*it)]);

        }

    }

  }

  template<class GridView>
  void
  GnuplotWriter<GridView>::writeRow(std::ostream & file, 
                                             const FieldVector<ctype,dimworld>& position, 
                                             const std::vector<float> & data) const
  {
    assert (data.size() == _names.size());
    // write position
    file << position << "\t";
    // write all data columns
    for (size_t j=0; j<data.size(); j++)
      file << data[j] << "\t";
    file << "\n";
  }

  /** \brief Add data (internal)
      \param t type of data (cellData/vertexData)
      \param data An ISTL compliant vector type
      \param name associated with the data
  */
  template<class GridView>
  template<class DataContainer>
  void
  GnuplotWriter<GridView>::addData(DataType t, const DataContainer& data, const std::string & name)
  {
    assert((t == cellData && _is.size(0) == data.size())
           || (t == vertexData && _is.size(GridView::dimension) == data.size()) );
    _names.push_back(name);

    // copy data to new container

    if (dimworld==1) {

        // data is transformed to nonconforming vertex data
        int c = 0;
        int shift = (t==vertexData?1:0);
        for (size_t i=0; i<_is.size(0); i++)
            {
                _data[c++].push_back(data[i]);
                _data[c++].push_back(data[i+shift]);
            };

    } else {

        // 2d: only vertex data is allowed
        for (size_t i=0; i<_is.size(dimworld); i++)
            _data[i].push_back(data[i]);

    }

  }
    
}
