/* ====================================================================
 * Copyright (c) 2003-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.
 * ====================================================================
 */

#ifndef _SC_PROJECT_H
#define _SC_PROJECT_H

// sc
#include "util/uuid.h"
#include "util/String.h"
#include "svn/Revision.h"

// sys
#include <vector>
#include <map>


const long UnusedId   = -4;
const long TrunkId    = -3;
const long BranchesId = -2;
const long TagsId     = -1;

class Project
{
public:
  enum ItemType
  {
    Item_Trunk,
    Item_Branches,
    Item_Tags,
    Item_WorkingCopy,
    Item_Repository,
    Item_None
  };

  enum SubItemType
  {
    SubItem_Flat,
    SubItem_Tree
  };

  /////////////////////////////////////////////////////////////////////////////
 
  /** SubItem represents a view in an Item. */
  class SubItem
  {
  public:
    SubItem();
    SubItem( const SubItem& );
    SubItem( long id, const sc::String& path );

    void operator=( const SubItem& );
    bool operator==( const SubItem& ) const;

    long getId() const;
    const sc::String& getPath() const;
    void setPath( const sc::String& path );
    SubItemType getType() const;
    void setType( SubItemType type );

    bool isNull() const;

  private:
    long        _id;
    SubItemType _type;
    sc::String  _path;
  };

  typedef std::vector<SubItem>   SubItems;
  typedef std::map<long,SubItem> MapIdSubItems;


  /** Item represents a bookmark in a Project. */
  class Item
  {
  public:
    Item();
    Item( const Item& );
    Item( long id, ItemType type, const sc::String& name, const sc::String& src );

    void operator=( const Item& );
    bool operator==( const Item& ) const;

    long  getId() const;
    ItemType getType() const;

    const sc::String& getName() const;
    const sc::String& getSource() const;

    /**
     * Set the item name.
     */
    void setName( const sc::String& );

    /**
     * Set the source path or url. If item is a working copy it will
     * replace all '\' with '/' in the source.
     */
    void setSource( const sc::String& );


    bool isWorkingCopy() const;
    bool isRepository() const;
    bool isTrunk() const;
    bool isBranches() const;
    bool isTags() const;
    bool isNull() const;

    // \name Options
    // @{
    long getSortPos() const;
    void setSortPos( long );

    /** run commands recursive */
    bool getRecursive() const;
    void setRecursive( bool );

    /** working copy, show updates */
    bool getUpdate() const;
    void setUpdate( bool );

    /** working copy, automatic update at startup */
    bool getAutoUpdate() const;
    void setAutoUpdate( bool );

    /** working copy, automatic status refresh */
    bool getAutoRefresh() const;
    void setAutoRefresh( bool );

    /** repository, revision */
    svn::RevisionPtr getRevision() const;
    void setRevision( svn::RevisionPtr );

    // \name Settings
    // @{
    void setViewHeader( const sc::String& header );
    const sc::String& getViewHeader() const;
    // @}

    // \name SubItems
    // @{
    const SubItem& createSubItem();

    bool hasSubItems() const;
    void delSubItem( long id );
    void getSubItems( SubItems& items ) const;
    void setSubItem( const SubItem& );
    const SubItem& getSubItem( long id ) const;
    // @}

  private:
    friend class Project;

    void setId( long );
    void setType( ItemType );
    void init();

  private:
    long             _id;
    ItemType         _type;
    sc::String       _name;
    sc::String       _source;

    // options
    long             _sortpos;
    bool             _recursive;
    bool             _update;
    bool             _autoRefresh;
    bool             _autoUpdate;
    svn::RevisionPtr _rev;

    // settings
    sc::String       _viewHeader;

    MapIdSubItems    _subItems;
  };

  /////////////////////////////////////////////////////////////////////////////

  typedef std::vector<Item> Items;
  typedef std::map<long,Item> MapIdItems;

  Project( const Uuid& id, const sc::String& name );
  Project( const Project& src );
  ~Project();

  void operator=( const Project& src );
  bool operator==( const Project& src ) const;

  const Uuid&       getId() const;
  const sc::String& getName() const;
  long              getIndex() const;
  long              getSortPos() const;

  const sc::String& getRepositoryUrl() const;
  const sc::String& getRepositoryName() const;
  const sc::String& getBranchesUrl() const;
  const sc::String& getBranchesName() const;
  const sc::String& getTagsUrl() const;
  const sc::String& getTagsName() const;

  const Item& getTrunkItem() const;
  const Item& getBranchesItem() const;
  const Item& getTagsItem() const;

  const sc::String& getCurWorkingCopyPath() const;  // obsolete?
  const sc::String& getCurWorkingCopyName() const;  // obsolete?
  long              getCurWorkingCopyId() const;
  const Item&       getCurWorkingCopy() const;
  const sc::String& getWorkingCopyPath( long id ) const;
  const sc::String& getWorkingCopyName( long id ) const;
  bool              isCurrentWorkingCopy( const Item& ) const;

  void setName( const sc::String& name );
  void setIndex( long );
  void setSortPos( long pos );

  void setTrunk( const Item& );
  void setBranches( const Item& );
  void setTags( const Item& );

  void setRepositoryUrl( const sc::String& url );
  void setRepositoryName( const sc::String& name );
  void setBranchesUrl( const sc::String& url );
  void setBranchesName( const sc::String& name );
  void setTagsUrl( const sc::String& url );
  void setTagsName( const sc::String& name );

  void setCurWorkingCopy( long id );

  const Item& createWorkingCopyItem();
  const Item& createRepositoryItem();
  void delItem( long id );
  void getItems( Items& items ) const;
  /**
   * Set a new or a modified item. If it is a new item is has to be created
   * by the @a createWorkingCopyItem() or @a createRepositoryItem() factory
   * methods.
   */
  void setItem( const Item& );
  const Item& getItem( long id ) const;
  void moveItem( long fromId, long toId );

  const sc::String& getItemName(long id) const;
  const sc::String& getItemSource(long id) const;

  void setItemName( long id, const sc::String& name );
  void setItemSource( long id, const sc::String& source );

  void preset();

private:
  Uuid       _id;
  sc::String _name;
  long       _index;             ///< config
  long       _sortpos;

  MapIdItems _items;

  long       _wcCurId;
};


#endif //  _SC_PROJECT_H
