/* ====================================================================
 * Copyright (c) 2008-2009  Martin Hauner
 *                          http://subcommander.tigris.org
 *
 * Subcommander is licensed as described in the file doc/COPYING, which
 * you should have received as part of this distribution.
 * ====================================================================
 *
 * Test that the tree below is properly filtered and refreshed in flat
 * mode. All dirs are unchanged all, files are changed. At first build
 * win32 etc are hidden. When we get to svn.rc we want build, win32
 * etc to get visible.
 *
 * Check that we get the correct data from model and proxy.
 * .
 * build
 * build/win32
 * build/win32/svn.rc
 * subversion
 * subversion/libsvn_client
 * subversion/libsvn_client/deprecated.c
 * subversion/libsvn_subr
 * subversion/libsvn_subr/error.c
 * subversion/libsvn_subr/win32_crashrpt.c
 */

#include "WcViewWithDeepChange.h"
#include "WcViewItemTest.h"
#include "util-test/AssertionTraitString.h"

// cppunit
#include <cppunit/TestSuite.h>
#include <cppunit/TestCaller.h>

// sc
#include "subcommander/WcViewItemModel.h"
#include "subcommander/WcViewTreeItemModel.h"
#include "subcommander/WcViewTreeProxyModel.h"
#include "util/String.h"

// qt
#include <QtCore/QVariant>


enum {
  RootFolder,
  RootFolderFolder,
  RootFolderFolders,
  RootFolderFolderItem,
  RootFolderFolders1Item,
  RootFolderFolders2Item,
};


void WcViewWithDeepChange::setUp()
{
  _model = new WcViewTreeItemModel( sc::String("invisible/svn"), new WcViewItemDataTest() );
  _proxy = new WcViewTreeProxyModel();
  _proxy->setSourceModel(_model);
  _proxy->setCurrentPath( sc::String("invisible/svn") );
  _proxy->setFilterFlat(true);
  TextStatusFilter filter;
  filter.set(StatusModified);
  _proxy->setFilterTextStatus(filter);

  // setup input data for the model
  setup(RootFolder,"invisible/svn",true,false);
  setup(RootFolder,"invisible/svn/build",true,false);
  setup(RootFolder,"invisible/svn/subversion",true,false);

  setup(RootFolderFolder,"invisible/svn/build",true,false);
  setup(RootFolderFolder,"invisible/svn/build/win32",true,false);

  setup(RootFolderFolders,"invisible/svn/subversion",true,false);
  setup(RootFolderFolders,"invisible/svn/subversion/libsvn_client",true,false);
  setup(RootFolderFolders,"invisible/svn/subversion/libsvn_subr",true,false);

  setup(RootFolderFolderItem,"invisible/svn/build/win32",true,false);
  setup(RootFolderFolderItem,"invisible/svn/build/win32/svn.rc",false,true);

  setup(RootFolderFolders1Item,"invisible/svn/subversion/libsvn_client",true,false);
  setup(RootFolderFolders1Item,"invisible/svn/subversion/libsvn_client/deprecated.c",false,true);

  setup(RootFolderFolders2Item,"invisible/svn/subversion/libsvn_subr",true,false);
  setup(RootFolderFolders2Item,"invisible/svn/subversion/libsvn_subr/error.c",false,true);
  setup(RootFolderFolders2Item,"invisible/svn/subversion/libsvn_subr/win32_crashrpt.c",false,true);
}

void WcViewWithDeepChange::tearDown()
{
  delete _model;
  delete _proxy;
}

void WcViewWithDeepChange::showAllAfterRootFolderAdd()
{
  insert( _model, RootFolder );

  QModelIndex idx = _model->index(0,0,QModelIndex());
  assertIndex( idx, "invisible/svn" );
  assertIndex( idx.child(0,0), "invisible/svn/build" );
  assertIndex( idx.child(1,0), "invisible/svn/subversion" );
  CPPUNIT_ASSERT_EQUAL( false, idx.child(2,0).isValid() );
}

void WcViewWithDeepChange::showAllAfterRootFolderFolderAdd()
{
  insert( _model, RootFolder );
  insert( _model, RootFolderFolder );

  QModelIndex idx = _model->index(0,0,QModelIndex());
  assertIndex( idx, "invisible/svn" );
  assertIndex( idx.child(0,0), "invisible/svn/build" );
  assertIndex( idx.child(1,0), "invisible/svn/subversion" );
  CPPUNIT_ASSERT_EQUAL( false, idx.child(2,0).isValid() );

  QModelIndex cidx0 = idx.child(0,0);
  assertIndex( cidx0.child(0,0), "invisible/svn/build/win32" );
  CPPUNIT_ASSERT_EQUAL( false, cidx0.child(1,0).isValid() );

  QModelIndex cidx1 = idx.child(1,0);
  CPPUNIT_ASSERT_EQUAL( false, cidx1.child(0,0).isValid() );
}

void WcViewWithDeepChange::showAllAfterRootFolderFoldersAdd()
{
  insert( _model, RootFolder );
  insert( _model, RootFolderFolder );
  insert( _model, RootFolderFolders );

  QModelIndex idx = _model->index(0,0,QModelIndex());
  assertIndex( idx, "invisible/svn" );
  assertIndex( idx.child(0,0), "invisible/svn/build" );
  assertIndex( idx.child(1,0), "invisible/svn/subversion" );
  CPPUNIT_ASSERT_EQUAL( false, idx.child(2,0).isValid() );

  QModelIndex cidx0 = idx.child(0,0);
  assertIndex( cidx0.child(0,0), "invisible/svn/build/win32" );
  CPPUNIT_ASSERT_EQUAL( false, cidx0.child(1,0).isValid() );

  QModelIndex cidx1 = idx.child(1,0);
  assertIndex( cidx1.child(0,0), "invisible/svn/subversion/libsvn_client" );
  assertIndex( cidx1.child(1,0), "invisible/svn/subversion/libsvn_subr" );
  CPPUNIT_ASSERT_EQUAL( false, cidx1.child(2,0).isValid() );
}

void WcViewWithDeepChange::showAllAfterRootFolderFolderItemAdd()
{
  insert( _model, RootFolder );
  insert( _model, RootFolderFolder );
  insert( _model, RootFolderFolders );
  insert( _model, RootFolderFolderItem );

  QModelIndex idx = _model->index(0,0,QModelIndex());
  assertIndex( idx, "invisible/svn" );
  assertIndex( idx.child(0,0), "invisible/svn/build" );
  assertIndex( idx.child(1,0), "invisible/svn/subversion" );
  CPPUNIT_ASSERT_EQUAL( false, idx.child(2,0).isValid() );

  QModelIndex cidx0 = idx.child(0,0);
  assertIndex( cidx0.child(0,0), "invisible/svn/build/win32" );
  assertIndex( cidx0.child(0,0).child(0,0), "invisible/svn/build/win32/svn.rc" );
  CPPUNIT_ASSERT_EQUAL( false, cidx0.child(0,0).child(1,0).isValid() );
  CPPUNIT_ASSERT_EQUAL( false, cidx0.child(1,0).isValid() );

  QModelIndex cidx1 = idx.child(1,0);
  assertIndex( cidx1.child(0,0), "invisible/svn/subversion/libsvn_client" );
  assertIndex( cidx1.child(1,0), "invisible/svn/subversion/libsvn_subr" );
  CPPUNIT_ASSERT_EQUAL( false, cidx1.child(2,0).isValid() );
}

void WcViewWithDeepChange::showAllAfterRootFolderFolders1ItemAdd()
{
  insert( _model, RootFolder );
  insert( _model, RootFolderFolder );
  insert( _model, RootFolderFolders );
  insert( _model, RootFolderFolderItem );
  insert( _model, RootFolderFolders1Item );

  QModelIndex idx = _model->index(0,0,QModelIndex());
  assertIndex( idx, "invisible/svn" );
  assertIndex( idx.child(0,0), "invisible/svn/build" );
  assertIndex( idx.child(1,0), "invisible/svn/subversion" );
  CPPUNIT_ASSERT_EQUAL( false, idx.child(2,0).isValid() );

  QModelIndex cidx0 = idx.child(0,0);
  assertIndex( cidx0.child(0,0), "invisible/svn/build/win32" );
  assertIndex( cidx0.child(0,0).child(0,0), "invisible/svn/build/win32/svn.rc" );
  CPPUNIT_ASSERT_EQUAL( false, cidx0.child(0,0).child(1,0).isValid() );
  CPPUNIT_ASSERT_EQUAL( false, cidx0.child(1,0).isValid() );

  QModelIndex cidx1 = idx.child(1,0);
  assertIndex( cidx1.child(0,0), "invisible/svn/subversion/libsvn_client" );
  assertIndex( cidx1.child(0,0).child(0,0), "invisible/svn/subversion/libsvn_client/deprecated.c" );
  CPPUNIT_ASSERT_EQUAL( false, cidx1.child(0,0).child(1,0).isValid() );

  assertIndex( cidx1.child(1,0), "invisible/svn/subversion/libsvn_subr" );
  CPPUNIT_ASSERT_EQUAL( false, cidx1.child(2,0).isValid() );
}

void WcViewWithDeepChange::showAllAfterRootFolderFolders2ItemAdd()
{
  insert( _model, RootFolder );
  insert( _model, RootFolderFolder );
  insert( _model, RootFolderFolders );
  insert( _model, RootFolderFolderItem );
  insert( _model, RootFolderFolders1Item );
  insert( _model, RootFolderFolders2Item );

  QModelIndex idx = _model->index(0,0,QModelIndex());
  assertIndex( idx, "invisible/svn" );
  assertIndex( idx.child(0,0), "invisible/svn/build" );
  assertIndex( idx.child(1,0), "invisible/svn/subversion" );
  CPPUNIT_ASSERT_EQUAL( false, idx.child(2,0).isValid() );

  QModelIndex cidx0 = idx.child(0,0);
  assertIndex( cidx0.child(0,0), "invisible/svn/build/win32" );
  assertIndex( cidx0.child(0,0).child(0,0), "invisible/svn/build/win32/svn.rc" );
  CPPUNIT_ASSERT_EQUAL( false, cidx0.child(0,0).child(1,0).isValid() );
  CPPUNIT_ASSERT_EQUAL( false, cidx0.child(1,0).isValid() );

  QModelIndex cidx1 = idx.child(1,0);
  assertIndex( cidx1.child(0,0), "invisible/svn/subversion/libsvn_client" );
  assertIndex( cidx1.child(0,0).child(0,0), "invisible/svn/subversion/libsvn_client/deprecated.c" );
  CPPUNIT_ASSERT_EQUAL( false, cidx1.child(0,0).child(1,0).isValid() );

  assertIndex( cidx1.child(1,0), "invisible/svn/subversion/libsvn_subr" );
  assertIndex( cidx1.child(1,0).child(0,0), "invisible/svn/subversion/libsvn_subr/error.c" );
  assertIndex( cidx1.child(1,0).child(1,0), "invisible/svn/subversion/libsvn_subr/win32_crashrpt.c" );
  CPPUNIT_ASSERT_EQUAL( false, cidx1.child(1,0).child(2,0).isValid() );
  CPPUNIT_ASSERT_EQUAL( false, cidx1.child(2,0).isValid() );
}


void WcViewWithDeepChange::showOnlyRootAfterRootFolderAdd()
{
  insert( _proxy, RootFolder );

  QModelIndex idx = _proxy->index(0,0);
  assertIndex( idx, "invisible/svn" );
  CPPUNIT_ASSERT_EQUAL( false, idx.child(0,0).isValid() );
  CPPUNIT_ASSERT_EQUAL( false, idx.child(1,0).isValid() );
}

void WcViewWithDeepChange::showOnlyRootAfterRootFolderFolderAdd()
{
  insert( _proxy, RootFolder );
  insert( _proxy, RootFolderFolder );

  QModelIndex idx = _proxy->index(0,0);
  assertIndex( idx, "invisible/svn" );
  CPPUNIT_ASSERT_EQUAL( false, idx.child(0,0).isValid() );
  CPPUNIT_ASSERT_EQUAL( false, idx.child(1,0).isValid() );
}

void WcViewWithDeepChange::showOnlyRootAfterRootFolderFoldersAdd()
{
  insert( _proxy, RootFolder );
  insert( _proxy, RootFolderFolder );
  insert( _proxy, RootFolderFolders );

  QModelIndex idx = _proxy->index(0,0);
  assertIndex( idx, "invisible/svn" );
  CPPUNIT_ASSERT_EQUAL( false, idx.child(0,0).isValid() );
  CPPUNIT_ASSERT_EQUAL( false, idx.child(1,0).isValid() );
}

void WcViewWithDeepChange::showPathToModifiedAfterRootFolderFolderItemAdd()
{
  insert( _proxy, RootFolder );
  insert( _proxy, RootFolderFolder );
  insert( _proxy, RootFolderFolders );
  insert( _proxy, RootFolderFolderItem );

  QModelIndex idx = _proxy->index(0,0);
  assertIndex( idx, "invisible/svn" );

  assertIndex( idx.child(0,0), "invisible/svn/build" );
  CPPUNIT_ASSERT_EQUAL( false, idx.child(1,0).isValid() );

  QModelIndex cidx = idx.child(0,0);
  assertIndex( cidx.child(0,0), "invisible/svn/build/win32" );
  CPPUNIT_ASSERT_EQUAL( false, cidx.child(1,0).isValid() );

  QModelIndex cidx2 = cidx.child(0,0);
  assertIndex( cidx2.child(0,0), "invisible/svn/build/win32/svn.rc" );
  CPPUNIT_ASSERT_EQUAL( false, cidx2.child(1,0).isValid() );
}

void WcViewWithDeepChange::showPathToModifiedAfterRootFolderFolders1ItemAdd()
{
  insert( _proxy, RootFolder );
  insert( _proxy, RootFolderFolder );
  insert( _proxy, RootFolderFolders );
  insert( _proxy, RootFolderFolderItem );
  insert( _proxy, RootFolderFolders1Item );

  QModelIndex idx = _proxy->index(0,0);
  assertIndex( idx, "invisible/svn" );

  assertIndex( idx.child(0,0), "invisible/svn/build" );
  assertIndex( idx.child(1,0), "invisible/svn/subversion" );
  CPPUNIT_ASSERT_EQUAL( false, idx.child(2,0).isValid() );

  assertIndex( idx.child(0,0).child(0,0), "invisible/svn/build/win32" );
  CPPUNIT_ASSERT_EQUAL( false, idx.child(0,0).child(1,0).isValid() );

  assertIndex( idx.child(1,0).child(0,0), "invisible/svn/subversion/libsvn_client" );
  CPPUNIT_ASSERT_EQUAL( false, idx.child(1,0).child(1,0).isValid() );

  assertIndex( idx.child(0,0).child(0,0).child(0,0), "invisible/svn/build/win32/svn.rc" );
  CPPUNIT_ASSERT_EQUAL( false, idx.child(0,0).child(0,0).child(1,0).isValid() );

  assertIndex( idx.child(1,0).child(0,0).child(0,0), "invisible/svn/subversion/libsvn_client/deprecated.c" );
  CPPUNIT_ASSERT_EQUAL( false, idx.child(1,0).child(0,0).child(1,0).isValid() );
}

void WcViewWithDeepChange::showPathToModifiedAfterRootFolderFolders2ItemAdd()
{
  insert( _proxy, RootFolder );
  insert( _proxy, RootFolderFolder );
  insert( _proxy, RootFolderFolders );
  insert( _proxy, RootFolderFolderItem );
  insert( _proxy, RootFolderFolders1Item );
  insert( _proxy, RootFolderFolders2Item );

  QModelIndex idx = _proxy->index(0,0);
  assertIndex( idx, "invisible/svn" );

  assertIndex( idx.child(0,0), "invisible/svn/build" );
  assertIndex( idx.child(1,0), "invisible/svn/subversion" );
  CPPUNIT_ASSERT_EQUAL( false, idx.child(2,0).isValid() );

  assertIndex( idx.child(0,0).child(0,0), "invisible/svn/build/win32" );
  CPPUNIT_ASSERT_EQUAL( false, idx.child(0,0).child(1,0).isValid() );
  assertIndex( idx.child(1,0).child(0,0), "invisible/svn/subversion/libsvn_client" );
  assertIndex( idx.child(1,0).child(1,0), "invisible/svn/subversion/libsvn_subr" );
  CPPUNIT_ASSERT_EQUAL( false, idx.child(1,0).child(2,0).isValid() );

  assertIndex( idx.child(0,0).child(0,0).child(0,0), "invisible/svn/build/win32/svn.rc" );
  CPPUNIT_ASSERT_EQUAL( false, idx.child(0,0).child(0,0).child(1,0).isValid() );

  assertIndex( idx.child(1,0).child(0,0).child(0,0), "invisible/svn/subversion/libsvn_client/deprecated.c" );
  CPPUNIT_ASSERT_EQUAL( false, idx.child(1,0).child(0,0).child(1,0).isValid() );

  assertIndex( idx.child(1,0).child(1,0).child(0,0), "invisible/svn/subversion/libsvn_subr/error.c" );
  assertIndex( idx.child(1,0).child(1,0).child(1,0), "invisible/svn/subversion/libsvn_subr/win32_crashrpt.c" );
  CPPUNIT_ASSERT_EQUAL( false, idx.child(1,0).child(1,0).child(2,0).isValid() );
}

void WcViewWithDeepChange::setup( long idx, const char* path, bool dir, bool changed )
{
  _items[idx].push_back(WcViewItemPtr(new WcViewItemTest(sc::String(path),dir,changed)));
}

void WcViewWithDeepChange::insert( WcViewItemModel* model, long dataIdx )
{
  model->remove( _items[dataIdx].front()->path() );
  model->insert( _items[dataIdx].front()->path(), _items[dataIdx] );
}

void WcViewWithDeepChange::assertIndex( const QModelIndex& idx, const char* expected )
{
  sc::String actual = idx.data(WcViewItemModel::NameRole).value<sc::String>();
  CPPUNIT_ASSERT_EQUAL( sc::String(expected), actual );
}



#if 0
  sc::String  name  = parent.data(WcViewItemModel::NameRole).value<sc::String>();
  printf("ToBeInserted (parent): %s\n", (const char*)name ); 
  for( int i = start; i <= end; i++ )
  {
    QModelIndex idx = parent.child( i, 0 );
    sc::String  child  = idx.data(WcViewItemModel::NameRole).value<sc::String>();

    printf("ToBeInserted (child): %s\n", (const char*)child ); 
  }
#endif
