/*********************************************************
** Copyright (c) 2005
** University of Washington
** Licensed under the terms set forth by University of
** Washington. If you did not sign such a license, you
** are using this software/code illegally and you do not
** have permission to use, modify, or redistribute
** this or any files in this software package.
**
** File: OrderingTest.h
**
**********************************************************/
#ifndef ORDERINGTEST_H
#define ORDERINGTEST_H

#include "UnitTestClass.h"
#include "ClusterNode.h"
#include "TestException.h"
#include "BasicCluster.h"
#include "ClusterException.h"
#include "OptimalOrdering.h"
#include "EisenOrdering.h"
#include "VectorTestClasses.h"

#include <iostream>
#include <sstream>
using namespace std;

class COrderingTest : public CUnitTestClass
{
 public:
  COrderingTest() : CUnitTestClass("OrderingTest"),
    m_ppData(NULL), m_rows(0), m_cols(0)
  {
  }

  ~COrderingTest()
    {
      if (NULL != m_ppData)
	{
	  for(int i = 0; i < m_rows; i++)
	    {
	      delete m_ppData[i];
	    }
	  delete [] m_ppData;
	}

    }

 private:
  TDoubleVector** m_ppData;
  int m_rows, m_cols;
  static string sData;

 protected:
  void RunTests()
  {
    Setup();
    TestEisen();
    TestOptimal();
  }

 private:
  void Setup()
    {
      // read in sData
      std::stringstream sstr(stringstream::in | stringstream::out);
      sstr << sData;

      CDelimitedMatrixReader reader;
      int rowCount;
      int rowLength;

      reader.Read(sstr, &m_rows, &m_cols, &m_ppData);
      cout << "(" << m_rows << " rows read)\n";
    }

  void TestEisen()
  {
    BeginTest("TestEisen");
    bool success = true;
    
    CEuclidean dist;
    CCentroidLinkage combine;

    CBasicCluster cluster((CDistanceFunction*)&dist, 
			  (CCombineDataFunction*)&combine);

    string expected = 
      "6\t6\t0\t0\t0\t0\t0\t0\t\n"
      "0\t0\t0\t0\t0\t0\t6\t6\t\n"
      "0\t0\t6\t6\t0\t0\t0\t0\t\n"
      "0\t6\t6\t0\t0\t0\t0\t0\t\n"
      "0\t0\t0\t6\t6\t0\t0\t0\t\n"
      "0\t0\t0\t0\t6\t6\t0\t0\t\n"
      "0\t0\t0\t0\t0\t6\t6\t0\t\n";

    try
    {
      CClusterNode* root = cluster.Cluster((void**)m_ppData, m_rows);

      stringstream sstr1(stringstream::in | stringstream::out);
      CVectorToStream display(&sstr1);
      cout << "\n";
      root->WalkLeaves(&display);

      // order results
      CEisenOrdering eisen;
      eisen.OrderLeaves(root, cluster.GetDistanceMatrix());

      // display results
      stringstream sstr2(stringstream::in | stringstream::out);
      CVectorToStream display2(&sstr2);
      
      cout << "\n";
      root->WalkLeaves(&display2);
      if(expected.compare(sstr2.str()) != 0)
	{
	  cout << " expected:\n<start>" << expected << "<end>\n";
	  cout << " expected1:\n<start>" << sstr1.str() << "<end>\n";
	  cout << "actual: \n<start>" << sstr2.str() << "<end>\n";
	  __throw_message("ordering not equal to expected");
	}
    }
    catch(CTestException *pEx)
    {
      success = false;
      cout << pEx->Message() << "\n";
      delete pEx;
    }
    catch(CClusterException *pEx)
    {
      success = false;
      cout << pEx->Message() << "\n";
      delete pEx;
    }
    catch(...)
    {
      success = false;
      cout << "something's wrong\n";

    }
    
    EndTest(success);
  }

  void TestOptimal()
  {
    BeginTest("TestOptimal");
    bool success = true;
    
    CEuclidean dist;
    CCentroidLinkage combine;

    CBasicCluster cluster((CDistanceFunction*)&dist, 
			  (CCombineDataFunction*)&combine);

    string expected = 
      "6\t6\t0\t0\t0\t0\t0\t0\t\n"
      "0\t6\t6\t0\t0\t0\t0\t0\t\n"
      "0\t0\t6\t6\t0\t0\t0\t0\t\n"
      "0\t0\t0\t6\t6\t0\t0\t0\t\n"
      "0\t0\t0\t0\t6\t6\t0\t0\t\n"
      "0\t0\t0\t0\t0\t6\t6\t0\t\n"
      "0\t0\t0\t0\t0\t0\t6\t6\t\n";

    try
    {
      CClusterNode* root = cluster.Cluster((void**)m_ppData, m_rows);

      stringstream sstr1(stringstream::in | stringstream::out);
      CVectorToStream display(&sstr1);
      cout << "\n";
      root->WalkLeaves(&display);

      // order results
      COptimalOrdering ordering;
      ordering.OrderLeaves(root, cluster.GetDistanceMatrix());

      // display results
      stringstream sstr2(stringstream::in | stringstream::out);
      CVectorToStream display2(&sstr2);
      
      cout << "\n";
      root->WalkLeaves(&display2);
      if(expected.compare(sstr2.str()) != 0)
	{
	  cout << " expected:\n<start>" << expected << "<end>\n";
	  cout << "actual: \n<start>" << sstr2.str() << "<end>\n";
	  __throw_message("ordering not equal to expected");
	}
    }
    catch(CTestException *pEx)
    {
      success = false;
      cout << pEx->Message() << "\n";
      delete pEx;
    }
    catch(CClusterException *pEx)
    {
      success = false;
      cout << pEx->Message() << "\n";
      delete pEx;
    }
    catch(...)
    {
      success = false;
      cout << "something's wrong\n";

    }
    
    EndTest(success);
  }

};

string COrderingTest::sData = 
  "0	0	0	0	6	6	0	0\n"	//4.5
  "0	0	6	6	0	0	0	0\n"	//6.5
  "0	0	0	0	0	6	6	0\n"	//5.5
  "0	6	6	0	0	0	0	0\n"	//6.5
  "0	0	0	6	6	0	0	0\n"	//3.5
  "6	6	0	0	0	0	0	0\n"	//0.5
  "0	0	0	0	0	0	6	6\n";	//6.5

#endif

