#include "stdafx.h"

#include "testgrt.h"
#include "grtpp.h"
#include "grt_test_utility.h"
#include "myx_util_functions.h"

#include "listdifference.h"

using namespace std;
using namespace tut;

BEGIN_TEST_DATA_CLASS(listdifference_test)
public:
  GRT grt;
END_TEST_DATA_CLASS

TEST_MODULE(listdifference_test, "0listdifference_test");

TEST_FUNCTION(2)
{
  int source[]= {1, 2};
  int target[]= {2, 1};
  typedef ListDifference<int, int*, int*> TestActions;
  TestActions actions;
  
  actions.parse_structure(source, source + UPPER_BOUND(source), target, target + UPPER_BOUND(target), std::equal_to<int>(), std::less<int>());
  assure(actions.moved.size() == 1);

  std::pair<int, int> indexes= actions.apply_moved(actions.moved.front());
  assure_equal(indexes.first, 0);
  assure_equal(indexes.second, 1);
}

TEST_FUNCTION(3)
{
  int source[]= {1, 2, 3};
  int target[]= {2, 3, 1};
  typedef ListDifference<int, int*, int*> TestActions;
  TestActions actions;

  actions.parse_structure(source, source + UPPER_BOUND(source), target, target + UPPER_BOUND(target), std::equal_to<int>(), std::less<int>());
  assure(actions.moved.size()==1);
  std::pair<int, int> indexes= actions.apply_moved(actions.moved.front());
  assure_equal(indexes.first, 0);
  assure_equal(indexes.second, 2);
}

TEST_FUNCTION(4)
{
  int source[]= {1, 2, 3};
  int target[]= {1, 2, 4, 3};
  typedef ListDifference<int, int*, int*> TestActions;
  TestActions actions;

  actions.parse_structure(source, source + UPPER_BOUND(source), target, target + UPPER_BOUND(target), std::equal_to<int>(), std::less<int>());
  assure(actions.added.size()==1);
  int ind= actions.apply_added(actions.added.front());
  assure_equal(ind, 2);
}

TEST_FUNCTION(5)
{
  int source[]= {1, 2, 3};
  int target[]= {1, 3};
  typedef ListDifference<int, int*, int*> TestActions;
  TestActions actions;

  actions.parse_structure(source, source + UPPER_BOUND(source), target, target + UPPER_BOUND(target), std::equal_to<int>(), std::less<int>());
  assure(actions.removed.size()==1);
  int ind= actions.apply_removed(actions.removed.front());
  assure_equal(ind, 1);
}

template<class T, class _InIt1, class _InIt2> inline
void test_apply_order(_InIt1 _First1, _InIt1 _Last1, _InIt2 _First2, _InIt2 _Last2, unsigned keep= 0)
{
#if 0
int x= 10000;
#else 
int x= 1;
#endif

  while (x--)
  {
    typedef ListDifference<T, _InIt1, _InIt2> TestActions;
    TestActions actions;
  
    actions.parse_structure(_First1, _Last1, _First2, _Last2, std::equal_to<T>(), std::less<T>());
  
    while (actions.added.size() + actions.removed.size() + actions.moved.size() > keep)
    {
      int x= rand();
      switch( x % 3 )
      {
      case 0:
        if (actions.added.size())
        {
          TestActions::AddActionSet::iterator iter= actions.added.begin() + x % actions.added.size();
          actions.apply_added(*iter);
          actions.added.erase(iter);
          break;
        }
      case 1:
        if (actions.moved.size())
        {
          TestActions::MoveActionSet::iterator iter= actions.moved.begin() + x % actions.moved.size();
          actions.apply_moved(*iter);
          actions.moved.erase(iter);
          break;
        }
      case 2:
        if (actions.removed.size())
        {
          TestActions::RemoveActionSet::iterator iter= actions.removed.begin() + x % actions.removed.size();
          actions.apply_removed(*iter);
          actions.removed.erase(iter);
          break;
        }
      }
    };
  
    std::vector<T> res(actions.item_count());
    actions.expand(res.begin());
    assure_containers_equal(_First2, _Last2, res.begin(), res.end());
  }
}

template<class P, class T>
bool mycmp(P it, T ref)
{
  return **it == *ref;
}

template<class T, class _InIt1, class _InIt2, class _InIt3> inline
void test_parse_reorder(_InIt1 _First1, _InIt1 _Last1,
    _InIt2 _First2, _InIt2 _Last2,
    _InIt2 _First3, _InIt3 _Last3)
{
  std::vector<_InIt1> out(min(_Last1 - _First1, _Last2 - _First2));
  std::vector<_InIt2> out2(out.size());
  out.erase(stdext::LCS(_First1, _Last1, _First2, _Last2, out.begin(), out2.begin(), std::equal_to<T>()), out.end());

  assure_containers_equal(out.begin(), out.end(), _First3, _Last3, mycmp<std::vector<_InIt1>::iterator, _InIt3>); 

  test_apply_order<T>(_First1, _Last1, _First2, _Last2);
}

TEST_FUNCTION(12)
{
  int source[]= {1, 2, 3, 4};
  int target[]= {2, 4, 5};

  test_apply_order<int>(source, source + UPPER_BOUND(source), target, target + UPPER_BOUND(target));
}

TEST_FUNCTION(13)
{
  int source[]= {1, 2, 3, 4, 5};
  int target[]= {2, 4, 5, 3, 1};

  test_apply_order<int>(source, source + UPPER_BOUND(source), target, target + UPPER_BOUND(target));
}

TEST_FUNCTION(14)
{
  const int source[] = {7, 5, 4, 4, 0, 1, 1, 2, 3, 4, 4, 5, 6, 7};
  const int target[] = {5, 6, 7, 0, 3, 2, 1, 4, 3, 3};

  bool thrown= false;
  try
  {
    test_apply_order<int>(source, source + UPPER_BOUND(source), target, target + UPPER_BOUND(target), 1);
  }
  catch(...)
  {
    thrown= true;
  }

  assure(thrown);
}

TEST_FUNCTION(15)
{
  const int source[] = {1};
  const int target[] = {1, 2};

  bool thrown= false;
  try
  {
    test_apply_order<int>(source, source + UPPER_BOUND(source), target, target + UPPER_BOUND(target), 1);
  }
  catch(...)
  {
    thrown= true;
  }

  assure(thrown);
}

TEST_FUNCTION(16)
{
  const int source[] = {0, 0, 1, 5, 2, 3, 4, 5, 6, 6, 7, 8, 9, 10, 6, 11, 12, 13, 14};
  const int target[] = {6, 5, 7, 10, 12, 99, 99, 0, 14, 4, 13, 11, 1, 2, 3, 8, 9, 87};

  test_apply_order<int>(source, source + UPPER_BOUND(source), target, target + UPPER_BOUND(target));
}

TEST_FUNCTION(17)
{
  const int source[] = {0};
  const int *target  = NULL;

  test_apply_order<int>(source, source + UPPER_BOUND(source), target, target + UPPER_BOUND(target));
}

TEST_FUNCTION(19)
{
  const int source[] = {1, 2, 3};
  const int target[] = {4, 4, 1, 2, 3};

  test_apply_order<int>(source, source + UPPER_BOUND(source), target, target + UPPER_BOUND(target));
}

TEST_FUNCTION(20)
{
  const double source[] = {1., 2., .3};
  const double target[] = {4., 4., 1., .2, 3.3};

  test_apply_order<double>(source, source + UPPER_BOUND(source), target, target + UPPER_BOUND(target));
}

TEST_FUNCTION(60)
{
  const int a[] = {0};
  const int *b = NULL;
  const int *expected = NULL;
  test_parse_reorder<int>(a, a + UPPER_BOUND(a), b, b + UPPER_BOUND(b), expected, expected + UPPER_BOUND(expected));
}


TEST_FUNCTION(61)
{
  const int a[] = {0, 1, 2, 3, 4};
  const int b[] = {3, 2, 0, 4, 1};
  const int expected[] = {3, 4};
  test_parse_reorder<int>(a, a + UPPER_BOUND(a), b, b + UPPER_BOUND(b), expected, expected + UPPER_BOUND(expected));
}

TEST_FUNCTION(62)
{
  const int a[] = {0, 1};
  const int b[] = {0, 1};
  const int expected[] = {0, 1};

  test_parse_reorder<int>(a, a + UPPER_BOUND(a), b, b + UPPER_BOUND(b), expected, expected + UPPER_BOUND(expected));
}

TEST_FUNCTION(63)
{
  const int a[] = {0, 1};
  const int b[] = {1, 0};
  const int expected[] = {1};

  test_parse_reorder<int>(a, a + UPPER_BOUND(a), b, b + UPPER_BOUND(b), expected, expected + UPPER_BOUND(expected));
}

TEST_FUNCTION(64)
{
  const int a[] = {0, 1, 2};
  const int b[] = {2, 1, 0};
  const int expected[] = {2};

  test_parse_reorder<int>(a, a + UPPER_BOUND(a), b, b + UPPER_BOUND(b), expected, expected + UPPER_BOUND(expected));
}

TEST_FUNCTION(65)
{
  const int a[] = {0, 1, 2};
  const int b[] = {0, 2, 1};
  const int expected[] = {0, 2};

  test_parse_reorder<int>(a, a + UPPER_BOUND(a), b, b + UPPER_BOUND(b), expected, expected + UPPER_BOUND(expected));
}

TEST_FUNCTION(66)
{
  const int a[] = {0, 1, 2, 3, 4, 5, 6, 7};
  const int b[] = {0, 1, 2, 3, 7, 4, 5, 6};
  const int expected[] = {0, 1, 2, 3, 4, 5, 6};

  test_parse_reorder<int>(a, a + UPPER_BOUND(a), b, b + UPPER_BOUND(b), expected, expected + UPPER_BOUND(expected));
}

TEST_FUNCTION(67)
{
  const int a[] = {0, 1, 2, 3, 4, 5, 6, 7};
  const int b[] = {6, 5, 4, 3, 2, 1, 0, 7};
  const int expected[] = {6, 7};

  test_parse_reorder<int>(a, a + UPPER_BOUND(a), b, b + UPPER_BOUND(b), expected, expected + UPPER_BOUND(expected));
}

TEST_FUNCTION(68)
{
  const int a[] = {0, 1, 2, 3};
  const int b[] = {1, 2, 3, 0};
  const int expected[] = {1, 2, 3};

  test_parse_reorder<int>(a, a + UPPER_BOUND(a), b, b + UPPER_BOUND(b), expected, expected + UPPER_BOUND(expected));
}


TEST_FUNCTION(69)
{
  const int a[] = {0, 1, 2, 3, 4, 5, 6, 7};
  const int b[] = {6, 5, 7, 0, 2, 1, 4, 3};
  const int expected[] = {0, 2, 4};

  test_parse_reorder<int>(a, a + UPPER_BOUND(a), b, b + UPPER_BOUND(b), expected, expected + UPPER_BOUND(expected));
}

TEST_FUNCTION(70)
{
  const int a[] = {0, 1, 2, 3, 4, 5, 6, 7};
  const int b[] = {5, 6, 7, 0, 2, 1, 4, 3};
  const int expected[] = {5, 6, 7};

  test_parse_reorder<int>(a, a + UPPER_BOUND(a), b, b + UPPER_BOUND(b), expected, expected + UPPER_BOUND(expected));
}

TEST_FUNCTION(71)
{
  const int a[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14};
  const int b[] = {6, 5, 7, 10, 12, 0, 14, 4, 13, 11, 1, 2, 3, 8, 9};
  const int expected[] = {0, 1, 2, 3, 8, 9};

  test_parse_reorder<int>(a, a + UPPER_BOUND(a), b, b + UPPER_BOUND(b), expected, expected + UPPER_BOUND(expected));
}
 

TEST_FUNCTION(72)
{
  const char* a = "some strange string is here";
  const char* b = "not sure here might be something readable";
  const char* expected = "o srge sting re";

  test_parse_reorder<char>(a, a + strlen(a), b, b + strlen(b), expected, expected + strlen(expected));
}

END_TESTS
