/**
 * ==========================================================================
 * Copyright (c) 2009  Martin Hauner
 *                     http://subcommander.tigris.org
 *
 * This file is part of Subcommander.
 *
 * Subcommander  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.
 *
 * Subcommander  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 Subcommander. If not, see <http://www.gnu.org/licenses/>.
 * ==========================================================================
 */

// sc
#include "ItemFolder.h"
#include "svn/Path.h"

// qt
#include <QtCore/QString>

// boost
#include <boost/multi_index_container.hpp>
#include <boost/multi_index/global_fun.hpp>
#include <boost/multi_index/mem_fun.hpp>
#include <boost/multi_index/ordered_index.hpp>
#include <boost/multi_index/random_access_index.hpp>
using namespace boost::multi_index;

namespace wcview
{ 

// helper function for the multi_index_container below.
/*static*/ const sc::String& ItemName( Item* item )
{
  return item->getName();
}

struct Pos{};
struct Name{};

typedef boost::multi_index_container<
  Item*,
  indexed_by<
    random_access<
      tag<Pos>
    >,
    ordered_unique<
      tag<Name>,
      global_fun<Item*, const sc::String&, &ItemName>
      // doesn't build with vs2008 (internal compiler error)
      //const_mem_fun<const Item*, const sc::String&, &Item::getName>
    >
  >
> TChilds;

static Index BadIndex = -1;

class ItemFolder::Childs
{
  typedef TChilds::nth_index<0>::type IndexByPos;
  typedef TChilds::nth_index<1>::type IndexByName;
  typedef TChilds::index_iterator<Name>::type NameIterator;
  typedef TChilds::index_iterator<Pos>::type PosIterator;

public:
  Childs ()
  {
  }

  Item* get (const sc::String& name)
  {
    const NameIterator& it = _childs.get<Name> ().find (name);

    if(it == _childs.get<Name> ().end ())
      return NULL;

    return *it;
  }

  Item* get (const Index& index)
  {
    if (index < 0 || index >= _childs.size ())
      return NULL;

    return _childs.get<Pos> ().at (index);
  }

  void append (Item* item)
  {
    _childs.push_back (item);
  }

  Index size () const
  {
    return _childs.size ();
  }

  Index toIndex (const sc::String& name) const
  {
    const NameIterator& it = _childs.get<Name> ().find (name);

    if(it == _childs.get<Name> ().end ())
      return BadIndex;

    return _childs.project<Pos> (it) - _childs.begin ();
  }

private:
  TChilds _childs;
};


ItemFolder::ItemFolder (const WcViewItemPtr& item, Item* parent)
: _item (item), _parent (parent)
{
  _childs = new Childs ();
}

ItemFolder::~ItemFolder ()
{
  delete _childs;
}

const sc::String& ItemFolder::getName () const
{
  return _item->path ();
}

const WcViewItemPtr& ItemFolder::getViewItem () const
{
  return _item;
}

Item* ItemFolder::getParent () const
{
  return _parent;
}

Index ItemFolder::getParentIndex () const
{
  if (!_parent)
    return 0;
  else
    return _parent->getChildIndex (_item->path ());
}

Index ItemFolder::getChildCount() const
{
  return _childs->size();
}

Item* ItemFolder::getChild (const Index& index) const
{
  Item* item = _childs->get (index);
  if (!item)
    throw BadIndexException (index);
  return item;
}

Item* ItemFolder::getChild (const sc::String& name) const
{
  Item* item = _childs->get (name);
  if (!item)
    throw BadNameException (name);
  return item;
}

Index ItemFolder::getChildIndex (const sc::String& name) const
{
  Index idx = _childs->toIndex (name);
  if (idx == BadIndex)
    throw BadNameException (name);
  return idx;
}

void ItemFolder::insertChild (Item* item)
{
  assert (item!=NULL);
  _childs->append (item);
}


#if 0
const Item* ItemFolder::getItem(const sc::String& path) const
{
  return _childs->get(path);
}
#endif

#if 0
Item* ItemFolder::findParentItem(const sc::String& path) const
{
  if(isDirectChild(path))
    return getItem(path);
  else
    return getItem(getIntermediatePath(path))->findParentItem(path);
}
#endif

#if 0
const Item* ItemFolder::addItem(const WcViewItemPtr& item)
{
  if(isDirectChild(item->path()))
    return addDirectChild(item);
  else
    return addDeepChild(item);
}
#endif

#if 0
bool ItemFolder::isDirectChild(const sc::String& path) const
{
  sc::String parent = svn::Path::getDirName(path);
  return parent == _item->path();
}

const Item* ItemFolder::addDirectChild(const WcViewItemPtr& item)
{
//  Item* newItem = new ItemFolder(item,this);
//  _childs->append(newItem);
//  return newItem;
  return NULL;
}

const Item* ItemFolder::addDeepChild(const WcViewItemPtr& item)
{
//  sc::String subPath = getIntermediatePath(item->path());
//  Item* citem = _childs->get(subPath);
//  return citem->addItem(item);
  return NULL;
}

sc::String ItemFolder::getIntermediatePath(const sc::String& path) const
{
  QString qPath = QString::fromUtf8(path);
  int idx = qPath.indexOf( '/', _item->path().getCharCnt()+1 );
  sc::String child = path.left(idx);
  return child;
}
#endif

} // namespace
