//
// C++ Interface: flowconnectorlist
//
// Description: 
//
//
// Author: David Saxton, Alan Grimes, Zoltan Padrah <zoltan.padrah@gmail.com>, (C) 2009
//
// Copyright: See COPYING file that comes with this distribution
//
//
#ifndef FLOWCONNECTORLIST_H
#define FLOWCONNECTORLIST_H

#include "flowconnector.h"

#include <QList>

class Connector;
class FlowConnector;

// these typedef's shoud go in a separate header one day
typedef QList< QPointer<Connector> > ConnectorList;


/**
 * @short a list of connector between FlowNodes
 * @author David Saxton, Alan Grimes, Zoltan Padrah <zoltan.padrah@gmail.com>
 *
 * This class implements a list of FlowConnector objects; this class fulfills two
 * requirements:
 * 1. it provides type safety for classes related to flowparts
 * 2. can be cast to a generic ConnectorList, to be used in other contexts
 * 
 * For QList interface see http://doc.trolltech.com/3.3/qlist.html
 */

/*
	Notations used in the source code:
	 O(n) : the method has this complexitiy
	 assert ? : in that method some assertions could be made, considering 
			that the two list should have the same contents
 */
 
class FlowConnectorList {
	
public :
	
	// cast operator, for casting it to ConnectorList
	operator ConnectorList() {
		return list;
	}
	
	// QList's interface
	typedef QPointer<FlowConnector> T;
	
#define CAST_POINTER 	(QPointer<Connector>)(Connector *)(FlowConnector *)
	
	typedef QList<T>::iterator iterator;
	typedef QList<T>::const_iterator const_iterator;
	typedef T value_type;
	typedef value_type * pointer;
	typedef const value_type * const_pointer;
	typedef value_type & reference;
	typedef const value_type & const_reference;
	typedef size_t size_type;
	
	FlowConnectorList () : list(), flowList() { }

	FlowConnectorList ( const QList<T> & l ) ; /* : flowList(l) { // O(n)
		FlowConnectorList::iterator it, end = flowList.end();
		for( it = flowList.begin(); it != end; it++)
			list.append( CAST_POINTER *it);
	} */

	/* FlowConnectorList ( const std::list<T> & l ) ; */ /* : flowList(l) {
		FlowConnectorList::iterator it, end = flowList.end();
		for( it = flowList.begin(); it != end; it++)
			list.append( CAST_POINTER *it);
	} */

	~FlowConnectorList () { }	// leak check ?

	QList<T> & operator= ( const QList<T> & l ) ; /* { // -> O(n)
		flowList = l;
		list.clear();
		FlowConnectorList::iterator it, end = flowList.end();
		for( it = flowList.begin(); it != end; it++)
			list.append( CAST_POINTER  *it);
		return flowList;
	} */

	/* QList<T> & operator= ( const std::list<T> & l ) ; */ /* {	// O(n)
		flowList = l;
		list.clear();
		FlowConnectorList::iterator it, end = flowList.end();
		for( it = flowList.begin(); it != end; it++)
			list.append( CAST_POINTER *it);
	
		return flowList;
	} */

	/* bool operator== ( const std::list<T> & l ) const ; */  /* {
		return flowList == l;
	} */

	bool operator== ( const QList<T> & l ) const {
		return flowList == l;
	}

	bool operator!= ( const QList<T> & l ) const {
		return flowList != l;
	}

	iterator begin () {
		return flowList.begin();
	}

	const_iterator begin () const {
		return flowList.begin(); // ? 
	}

	const_iterator constBegin () const {
		return flowList.constBegin();
	}

	iterator end () {
		return flowList.end();
	}

	const_iterator end () const {
		return flowList.end(); 	// ?
	}

	const_iterator constEnd () const {
		return flowList.constEnd();
	}

	iterator insert ( iterator it, const T & x ) ; /* {	// O(n)
		list.insert(  convertIterator( it ), CAST_POINTER x);
		return flowList.insert(it,x);
	} */

	uint remove ( const T & x ) ; /* {
		list.remove( CAST_POINTER  x);
		return flowList.remove(x);
	} */

	void clear () {
		flowList.clear();
		list.clear();
	}

	QList<T> & operator<< ( const T & x ) ; /* {
		list << CAST_POINTER  x;
		return flowList << x;
	} */

	size_type size () const {	// assert ?
		return flowList.size();
	}

	bool empty () const {		// assert ?
		return flowList.empty();
	}

	void push_front ( const T & x ) ; /* {
		list.push_front(CAST_POINTER x);
		flowList.push_front(x);
	} */

	void push_back ( const T & x ) ; /* {
		list.push_back(CAST_POINTER x);
		flowList.push_back(x);
	} */

	iterator erase ( iterator it ){		// O(n)
		list.erase( convertIterator(it) );
		return flowList.erase(it);
	}

	iterator erase ( iterator first, iterator last ){	// O(n)
		list.erase( convertIterator(first), convertIterator(last) );
		return flowList.erase(first, last);
	}

	reference front () {
		return flowList.front();
	}

	const_reference front () const {
		return flowList.front();
	}

	reference back () {
		return flowList.back();
	}

	const_reference back () const {
		return flowList.back();
	}

	void pop_front () {
		flowList.pop_front();
		list.pop_front();
	}

	void pop_back () {
		flowList.pop_back();
		list.pop_back();
	}

	/* void insert ( iterator pos, size_type n, const T & x ) ; */ /* { 	// O(n)
		list.insert( convertIterator(pos) ,n, CAST_POINTER x); 
		flowList.insert(pos,n,x);
	} */

	QList<T> operator+ ( const QList<T> & l ) const {
		return flowList + l;
	}

	QList<T> & operator+= ( const QList<T> & l ) ; /* {	// O(n)
		const_iterator end = l.end();
		for(const_iterator it = l.begin(); it != end; it++)
			list.append( CAST_POINTER  *it );
		return flowList += l;
	} */

	/* iterator fromLast () ; */ /* {
		return flowList.fromLast();
	} */

	/* const_iterator fromLast () const ; */ /* {
		return flowList.fromLast();
	} */

	bool isEmpty () const {
		return flowList.isEmpty();
	}

	iterator append ( const T & x ) ; /* {
		list.append(CAST_POINTER x);
		// return flowList.append(x);
        flowList.append(x);
        iterator ret = flowList.end();
        --ret;
        return ret;
	} */

	iterator prepend ( const T & x ) ; /* {
		list.prepend(CAST_POINTER x);
		//return flowList.prepend(x);
        flowList.prepend(x);
        return flowList.begin();
	} */

	iterator remove ( iterator it ){
	// -> O(n)
		list.erase( convertIterator( it ) );
		return flowList.erase(it);
	}

	T & first () {	// assert ?
		return flowList.first();
	}

	const T & first () const {			// assert ?
		return flowList.first();
	}

	T & last () {					// assert ?
		return flowList.last();
	}

	const T & last () const {			// assert ?
		return flowList.last();
	}

	T & operator[] ( size_type i ) {		// assert ?
		return flowList[i];
	}

	const T & operator[] ( size_type i ) const {	// assert ?
		return flowList[i];
	}

	iterator at ( size_type i ) {			// assert ?
		//return flowList.at(i);
        iterator ret = flowList.begin();
        ret += i;
        return ret;
	}

	const_iterator at ( size_type i ) const {	// assert ?
		//return flowList.at(i);
        const_iterator ret = flowList.constBegin();
        ret += i;
        return ret;
	}

	iterator find ( const T & x ) {			// assert ?
        int i = flowList.indexOf(x);
        return (i == -1 ? flowList.end() : (flowList.begin()+i));
		//return flowList.find(x); // 2018.11.30
	}

	const_iterator find ( const T & x ) const {	// assert ?
        int i = flowList.indexOf(x);
        return (i == -1 ? flowList.end() : (flowList.begin()+i));
		//return flowList.find(x); // 2018.11.30
	}

	iterator find ( iterator it, const T & x ) {	// assert ?
		//return flowList.find(it, x); // 2018.11.30
        int i = flowList.indexOf(x, it - flowList.begin());
        return i == -1 ? flowList.end() : flowList.begin()+i;
	}
 
	const_iterator find ( const_iterator it, const T & x ) const {	// assert ?	
		//return flowList.find(it, x); // 2018.11.30
        int i = flowList.indexOf(x, it - flowList.begin());
        return i == -1 ? flowList.end() : flowList.begin()+i;
	}

	int indexOf ( const T & x ) const {		// assert ?
		return flowList.indexOf(x);
	}

	size_type contains ( const T & x ) const {
		//return flowList.contains(x);
        return flowList.count(x);
	}

	size_type count () const {			// assert ?
		return flowList.count();
	}

	QList<T> & operator+= ( const T & x ) ; /* {
		list += CAST_POINTER x;
		return flowList += x;
	} */

private: 
	ConnectorList list;
	QList< T > flowList;
	
	/**
	 *    Converts an iterator from FlowConnector list to Connector list. Complexity: O(n) !
	 * @param orig original iterator from FlowConnector list
	 * @return iterator converted to Connector list
	 */
	ConnectorList::iterator convertIterator(QList< T >::iterator orig){
		ConnectorList::iterator it2 = list.begin();
		for(QList< T >::iterator it = flowList.begin(); it != orig; it++)
			it2++;
		return it2;
	}
	
};

#endif
