//==========================================================================
//
//   embedding.h
//
//==========================================================================
// $Id: embedding.h,v 1.15 2000/01/05 16:32:35 raitner Exp $

#ifndef __EMBEDDING__H
#define __EMBEDDING__H

#include <GTL/GTL.h>
#include <GTL/graph.h>
#include <GTL/st_number.h>
#include <GTL/symlist.h>

__GTL_BEGIN_NAMESPACE

/**
 * @short ordered adjacency lists as a result of planarity testing.
 * 
 * It is known that if a graph is planar the adjacency list of every node can be 
 * ordered in such a way that it reflects the order the adjacent edges will have 
 * in a planar drawing around the node. Although the tested graph might have been 
 * directed the planar embedding one gets will always correspond to the underlying 
 * undirected graph, i.e. an edge from <code>n1</code> to <code>n2</code> will 
 * occurr in both adjacency lists. 
 * 
 */
class GTL_EXTERN planar_embedding 
{
public:
    typedef symlist<edge> adj_list;
    typedef symlist<edge>::iterator iterator;

private:
    /**
     * Creates an empty planar embedding not related to any graph. Please note that 
     * at the moment planar embedding are thought as an output of planarity testing, 
     * this why they can't be constructed from scratch. 
     */
    planar_embedding () : G (0) { };


public:
    /**
     * Make this object a copy of <code>em</code>
     *
     * @param <code>em</code> planar embedding
     */
    planar_embedding (const planar_embedding& em);

    /**
     * Destructor
     */
    virtual ~planar_embedding () { };

    /**
     * Assigns <code>em</code> to this object. All former information in this 
     * object will be deleted.
     *
     * @param <code>em</code> 
     * @return reference to this object.
     */
    planar_embedding& operator= (const planar_embedding& em); 
    
private:
    /**
     * Initializes adjacency lists.
     * 
     * @param <code>G</code> graph 
     */
    void init (graph& G);

    /**
     * Turns adjacency list of node <code>n</code>
     *
     * @param <code>n</code> node.
     */
    void turn (node n);

    /**
     * Insert edge <code>e</code> at the end of adjacency list of <code>n</code>.
     *
     * @param <code>n</code> node 
     * @param <code>e</code> edge to be inserted 
     * @return iterator to position of insertion
     */
    iterator push_back (node n, edge e);

    /**
     * Insert edge <code>e</code> at the beginning of adjacency list of <code>n</code>.
     *
     * @param <code>n</code> node 
     * @param <code>e</code> edge to be inserted 
     * @return iterator to position of insertion
     */
    iterator push_front (node n, edge e);

    /**
     * Insert selfloop <code>e</code>. Not used at the moment 
     *
     * @param <code>e</code> selfloop 
     */
    void insert_selfloop (edge e);

    /**
     * Returns position of edge <code>e</code> in adjacency list of node <code>n</code>.
     *
     * @param <code>n</code> node
     * @param <code>e</code> adjacent edge.
     * @return position of <code>e</code>
     */
    iterator& pos (node, edge);

public:
    /**
     * Returns reference to ordered adjacency list of node <code>n</code>
     *
     * @param <code>n</code> node
     * @return ordered adjacency list.
     */
    adj_list& adjacency (node n) 
	{ return adj[n]; }

    /**
     * Returns reference to ordered adjacency list of node <code>n</code>
     *
     * @param <code>n</code> node
     * @return ordered adjacency list.
     */
    const adj_list& adjacency (node n) const 
	{ return adj[n]; }


    /**
     * Start iteration through adjacency list of node <code>n</code>.
     *
     * @param <code>n</code> node.
     * @return start iterator.
     */
    iterator adj_edges_begin (node n)
	{ return adj[n].begin(); } 

    /**
     * End of iteration through adjacency list of node <code>n</code>.
     *
     * @param <code>n</code> node.
     * @return one-past the end iterator.
     */
    iterator adj_edges_end (node n)
	{ return adj[n].end(); }

    /**
     * Returns the cyclic successor of edge <code>e</code> in the adjacency list
     * of node <code>n</code>.
     *
     * @param <code>n</code> node
     * @param <code>e</code> edge adjacent to <code>n</code>
     * @return edge following <code>e</code> in adjacency of <code>n</code>
     */
    edge cyclic_next (node n, edge e);

    /**
     * Returns the cyclic predecessor of edge <code>e</code> in the adjacency list
     * of node <code>n</code>.
     *
     * @param <code>n</code> node
     * @param <code>e</code> edge adjacent to <code>n</code>
     * @return edge preceding <code>e</code> in adjacency of <code>n</code>
     */
    edge cyclic_prev (node n, edge e);


    /**
     * Writes embedding with st-numbers as given by <code>st</code> to <code>os</code>.
     *
     * @param <code>os</code> output stream
     * @param <code>st</code> st-numbers
     */
    void write_st (ostream& os, st_number& st);

    /**
     * Returns list of selfloops contained in the graph. These will not occur in
     * the adjacency lists.
     *
     * @return list of selfloops.
     */
    list<edge>& selfloops () 
    { return self; }

    /**
     * Returns list of selfloops contained in the graph. These will not occur in
     * the adjacency lists.
     *
     * @return list of selfloops.
     */
    const list<edge>& selfloops () const
    { return self; }

    /**
     * Returns list of multiple edges contained in the graph. These are edges for 
     * which there is already another edge connecting the same endpoints is contained 
     * in the adjacency lists. Please note that the notion "connecting" is meant in an
     * undirected sense. These edges will not occur it the adjacency lists.
     *
     * @return list of multiple edges.
     */
    list<edge>& multiple_edges () 
    { return multi; }

    /**
     * Returns list of multiple edges contained in the graph. These are edges for 
     * which there is already another edge connecting the same endpoints is contained 
     * in the adjacency lists. Please note that the notion "connecting" is meant in an
     * undirected sense. These edges will not occur it the adjacency lists.
     *
     * @return list of multiple edges.
     */
    const list<edge>& multiple_edges () const
    { return multi; }

    /**
     * Used for debugging only. Checks whether this is a correct planar 
     * embedding by checking the faces of the graph, i.e. at any node starting with an
     * arbitrary adjacent edge and advancing along <code>cyclic_next</code> the start 
     * node must be met through the edge given by <code>cyclic_prev</code> of the edge
     * we started with. 
     *
     * @return true iff embedding is correct.
     */
    bool check ();

    friend class planarity;
    friend class pq_tree;

    GTL_EXTERN friend ostream& operator<< (ostream&, planar_embedding&);

private:
    // graph
    graph* G;

    // adjacency lists
    node_map<adj_list> adj;

    // positions of edges in its source's adjacency list
    edge_map<adj_list::iterator> s_pos;

    // positions of edges in its target's adjacency list
    edge_map<adj_list::iterator> t_pos;

    // selfloops
    list<edge> self;

    // multiple edges
    list<edge> multi;
};


// class face
// {    
// public:
//     face (planar_embedding& em, node n, edge e) : embed (em),
// 	start (n), first (e) { }
//     virtual ~face () { }

// private:    
//     planar_embedding& embed;
//     node start;
//     edge first;

//     friend class planar_embedding;
// };

// struct _face_iterator
// {


//     face& _face;
// };

__GTL_END_NAMESPACE

#endif

//--------------------------------------------------------------------------
//   end of file
//--------------------------------------------------------------------------
