
/***************************************************************************
   copyright            : (C) 2006 by David Nolden
   email                : david.nolden.kdevelop@art-master.de
***************************************************************************/

/***************************************************************************
 *                                                                         *
 *   This program 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.                                   *
 *                                                                         *
 ***************************************************************************/

#ifndef __SIMPLETYPE_H__
#define __SIMPLETYPE_H__

#include <set>

#include "bithelpers.h"
#include "stringhelpers.h"
#include "completiondebug.h"
#include "typedesc.h"
#include "declarationinfo.h"
#include <tqpair.h>

#include "cpp_tags.h"
#include "codemodel.h"

#define NOBACKTRACE

extern TQString globalCurrentFile;

using namespace CompletionDebug;
using namespace BitHelpers;
using namespace StringHelpers;

class SimpleTypeImpl;
class SimpleTypeNamespace;
class SimpleTypeFunctionInterface;

typedef TDESharedPtr<SimpleTypeImpl> TypePointer;

///if this is set, imported items will get their parent set to the node they were acquired through(which may increase the overall count of items, decrease the caching-performance, and may create other problems in locating stuff)
//#define PHYSICAL_IMPORT

enum Repository {
  RepoCodeModel,
  RepoCatalog,
  RepoStringList,
  RepoBoth,
  RepoUndefined
};

class BuiltinTypes {
  public:
    ///This should be used for checking whether a type is builtin
    static bool isBuiltin( const TypeDesc& desc );
    ///If it is a builtin type this returns a short description of the type
    static TQString comment( const TypeDesc& desc );
    BuiltinTypes();
  private:
    static TQMap<TQString, TQString> m_types;
};


/**
    A Type can be invalid( hasNode() returns false ) but still have a desc. In that case, the desc is the
    nearest point reached in the resolution of the type.
 
    Warning: The types are not copied when they are assigned to each other,
    they manage internal references, so just changing a type may cause bugs.
    Use makePrivate() before changing. */

class SimpleType {
  public:

    friend class SimpleTypeImpl;

    SimpleType( const SimpleType& rhs ) {
      *this = rhs;
    }

    SimpleType( const TQStringList& scope, const HashedStringSet& files, Repository rep = RepoUndefined ) : m_resolved( false ) {
      init( scope, files, rep );
    }

    SimpleType( const TQString& text,const HashedStringSet& files, Repository rep = RepoUndefined ) : m_resolved( false ) {
      init( splitType( text ), files, rep );
    };

    SimpleType( Repository rep = RepoUndefined ) : m_resolved( false ) {
      init( TQStringList(), HashedStringSet(), rep );
    };

    SimpleType( SimpleTypeImpl* ip ) : m_type( TypePointer( ip ) ), m_resolved( true ) {}

    SimpleType( ItemDom item );

    bool operator < ( SimpleType& rhs );

    /*SimpleType( Tag tag );*/

    SimpleTypeImpl* operator -> () const {
      resolve();
      return &( *m_type );
    }

    TypePointer get
      () const {
        resolve();
        return m_type;
      }

    SimpleTypeImpl& operator * () const {
      resolve();
      return *m_type;
    }

    SimpleType& operator = ( const SimpleType& rhs ) {
      m_type = rhs.m_type;
      m_resolved = rhs.m_resolved;
      m_includeFiles = rhs.m_includeFiles;
      return *this;
    }

    /** Just compares the scope */
    bool operator == ( const SimpleType& rhs ) const {
      return scope() == rhs.scope();
    }

    void makePrivate();

    operator TQString() const {
      return str();
    }

    ///lazily returns the scope
    const TQStringList& scope() const;

    const TQString str() const;

    ///valid() does not check whether the type was found in some model,
    ///it just checks whether this theoretically represents a type.
    inline operator bool () const {
      return valid();
    }

    bool valid() const {
      return !scope().isEmpty();
    }

	static TypePointer globalNamespace() {
		return m_globalNamespace;
	}

    static void setGlobalNamespace( TypePointer tp ) {
      m_globalNamespace = tp;
    }

    static void resetGlobalNamespace() {
      m_globalNamespace = 0;
    }

    ///Since many cross-references are possible, this function breaks them all so that all SimpleTypeImpls can free themselves.
    static void destroyStore();

  private:

    void init( const TQStringList& scope, const HashedStringSet& files, Repository rep );

    void resolve( Repository rep = RepoUndefined ) const ;

    HashedStringSet m_includeFiles;

    mutable TypePointer m_type;
    mutable bool m_resolved;
    static TypePointer m_globalNamespace; ///this is bad, but with the current parser we can't clearly determine the correct global-namespace for each class/file
    typedef std::set
      <SimpleTypeImpl*> TypeStore ;
    static TypeStore m_typeStore; ///This is necessary because TypeDescs ind SimpleTypeImpls can have cross-references, and thereby make themselves unreleasable, so each SimpleTypeImpl is stored in this list and destroyed at once by SimpleTypeConfiguration( it breaks all references )
    static TypeStore m_destroyedStore;

    static void registerType( SimpleTypeImpl* tp ) {
      if ( !tp )
        return ;
      m_typeStore.insert( tp );
    }

    static void unregisterType( SimpleTypeImpl* tp ) {
      TypeStore::iterator it = m_typeStore.find( tp );
      if ( it != m_typeStore.end() )
        m_typeStore.erase( it );
      else
        m_destroyedStore.erase( tp );
    }
};


class SimpleTypeConfiguration {
  bool m_invalid;
  public:
    SimpleTypeConfiguration( TQString currentFileName = "" ) : m_invalid( false ) {
      globalCurrentFile = currentFileName;
      dbgState.clearCounter();
    }

    void setGlobalNamespace( TypePointer globalNamespace );

    virtual ~SimpleTypeConfiguration() {
      if( !m_invalid ) {
        SimpleType::resetGlobalNamespace();
        SimpleType::destroyStore();
      }
    }
    void invalidate() {
      m_invalid = true;
    }
};


class SimpleTypeImpl : public TDEShared {
    /*enum ResolutionFlags {
       NoFlag = 0,
       HadTypedef = 1,
       HadTemplate = 2,
       HadAlias = 3
     };*/

  public:
    typedef TDESharedPtr<SimpleTypeImpl> TypePointer;

    SimpleTypeImpl( const TQStringList& scope ) : m_resolutionCount( 0 ), m_resolutionFlags( NoFlag ), m_scope( scope ) {
	  setScope( m_scope );
      checkTemplateParams();
      reg();
    }

    SimpleTypeImpl( const TypeDesc& desc ) : m_resolutionCount( 0 ), m_resolutionFlags( NoFlag ), m_desc( desc ) {
      if ( !m_desc.name().isEmpty() )
        m_scope.push_back( m_desc.name() );
      else
        m_scope.push_back( "BAD_NAME" );
      reg();
    }

    SimpleTypeImpl( ) : m_resolutionCount( 0 ), m_resolutionFlags( NoFlag ) {
      reg();
    };

	///Returns the template-specialization-string for classes
	virtual TQString specialization() const {
		return TQString();
	}

    class TemplateParamInfo {
      public:
        struct TemplateParam {
          TQString name;
          TypeDesc def;
          TypeDesc value;
          int number;
          TemplateParam() : number( 0 ) {}
        }
        ;

        TemplateParamInfo( ) {}
	    
        bool getParam( TemplateParam& target, TQString name ) const;

        bool getParam( TemplateParam& target, int number ) const;

        void removeParam( int number );

        void addParam( const TemplateParam& param );

	    int count() const;
	    
      private:
        TQMap<int, TemplateParam> m_paramsByNumber;
        TQMap<TQString, TemplateParam> m_paramsByName;
    };

    int resolutionCount() {
      return m_resolutionCount;
    }

    bool hasResolutionFlag( ResolutionFlags flag ) {
      return m_resolutionFlags & flag;
    }

    enum Operator {
      ArrowOp,
      StarOp,
      AddrOp,
      IndexOp,
      ParenOp,
      NoOp
  };

    static CppCodeCompletion* data;
    TypePointer m_masterProxy; ///If this is only a slave of a namespace-proxy, this holds the proxy.

    virtual ~SimpleTypeImpl() {
      unreg();
    }

    virtual Repository rep() {
      return RepoStringList;
    }

    ///Returns the function-interface if this is a function, else zero
    SimpleTypeFunctionInterface* asFunction();

    virtual bool isNamespace() const {
      return false;
    };

    virtual TQString comment() const {
      return "";
    };


    ///Sets the parent of the given slave to either this class, or the proxy of this class
    virtual void setSlaveParent( SimpleTypeImpl& slave );

    void setMasterProxy( TypePointer t ) {
      m_masterProxy = t;
    }

    TypePointer masterProxy() const {
        return m_masterProxy;
    }

    ///@todo remove this and use getTemplateParamInfo instead
    virtual const LocateResult findTemplateParam( const TQString& /*name*/ ) {
		return LocateResult();
    }

    virtual TemplateParamInfo getTemplateParamInfo() {
      return TemplateParamInfo();
    }

    virtual void parseParams( TypeDesc desc );

    virtual void takeTemplateParams( TypeDesc desc );

    ///Returns whether the type is really resolved( corresponds to an item in some model )
    virtual bool hasNode() const {
      return false;
    };

    virtual DeclarationInfo getDeclarationInfo() {
      return DeclarationInfo();
    }

    virtual TypePointer clone() {
      return new SimpleTypeImpl( this );
    }

  private:
    int m_resolutionCount;
    ResolutionFlags m_resolutionFlags;

    SimpleTypeImpl( const SimpleTypeImpl& /*rhs*/ ) : TDEShared() {}

    SimpleTypeImpl& operator = ( const SimpleTypeImpl& /*rhs*/ ) {
      return * this;
    }


    void addResolutionFlag ( ResolutionFlags flag ) {
      m_resolutionFlags = ( ResolutionFlags ) ( m_resolutionFlags | flag );
    }

    void removeResolutionFlag( ResolutionFlags flag ) {
      m_resolutionFlags = remFlag( m_resolutionFlags, flag );
    }

    void increaseResolutionCount() {
      ++m_resolutionCount;
    }

    void setResolutionCount( int val ) {
      m_resolutionCount = val;
    }
#ifndef NOBACKTRACE
    TQString create_bt;
#endif

    inline TQString createInfo() const {
#ifndef NOBACKTRACE
      return "\n" + create_bt + "\n";
#endif

      return "";
    }

    void reg() {
#ifndef NOBACKTRACE
      create_bt = kdBacktrace();
#endif

      SimpleType::registerType( this );
    }

    void unreg() {
      SimpleType::unregisterType( this );
    }

  protected:
    virtual void invalidateCache() {}
    ;

    ///Secondary cache also depends on the surrounding
    virtual void invalidateSecondaryCache() {}

    virtual void setSecondaryCacheActive( bool active ) {
      Q_UNUSED( active );
    }

    ///Primary cache is the one associated only with this object. It must only be cleared
    ///when the object pointed to changes
    virtual void invalidatePrimaryCache( bool onlyNegative = false ) {}

    static TQString operatorToString( Operator op );

  public:
    /*
    operator TQString() const {
        return str();
    }

    inline operator TQStringList() const {
        return m_scope;
    }*/

    int functionDepth() const {
      return m_desc.pointerDepth();
    }

    void setFunctionDepth( int pc ) {
      m_desc.setPointerDepth( pc );
    }

    void decreaseFunctionDepth() {
      m_desc.setPointerDepth( m_desc.pointerDepth() - 1 );
    }

    int pointerDepth() const {
      return m_desc.pointerDepth();
    }

    void setPointerDepth( int pc ) {
      m_desc.setPointerDepth( pc );
    }


    ///returns the scope(including own name) as string
    TQString str() const {
      if ( m_scope.isEmpty() )
        return "";
      return m_scope.join( "::" );
    }

    ///returns the scope(including own name) as string-list
    inline const TQStringList& scope() const {
      return m_scope;
    }

	///Returns the scope including template-specialization
	TQStringList specializedScope() const {
		TQStringList ts = m_scope;
		if( !ts.isEmpty() ) {
			TQString s = ts.back() + specialization();
			ts.pop_back();
			ts.push_back( s );
		}
		return ts;
	}

    ///sets the parent-type(type this one is nested in)
    void setParent( TypePointer parent ) {
      if( parent == m_parent ) return;
      invalidateSecondaryCache();
      if ( &( *parent ) == this ) {
        kdDebug( 9007 ) << "setSlaveParent error\n" << kdBacktrace() << endl;
        return ;
      }

      m_parent = parent;
    }

    ///returns whether the type has template-parameters, or one of the parent-types has template-parameters.
    bool usingTemplates() const {
      return !m_desc.templateParams().isEmpty() || ( m_parent && m_parent->usingTemplates() );
    }

    ///This function should add aliases as well as namespace-imports into the given namespace
    virtual void addAliasesTo( SimpleTypeNamespace* ns ) {
    }

    ///An abstract class for building types lazily
  struct TypeBuildInfo : public TDEShared {
      TypePointer buildCached() {
        if ( m_cache )
          return m_cache;
        else {
          m_cache = build();
          return m_cache;
        }
      }

	  void setCache( const TypePointer& type ) {
		  m_cache = type;
	  }

      virtual TypePointer build() = 0;

      virtual ~TypeBuildInfo() {}

      TypeBuildInfo() {}
    private:

      TypePointer m_cache;

      TypeBuildInfo& operator =( const TypeBuildInfo& rhs ) {
        Q_UNUSED( rhs );
        return *this;
      }
      TypeBuildInfo( const TypeBuildInfo& rhs ) : TDEShared() {
        Q_UNUSED( rhs );
      }
    };

    ///A class that stores information about a member of some SimpleType
    class MemberInfo {
        TDESharedPtr<TypeBuildInfo> m_build;
      public:

        enum MemberType {
          NotFound = 0,
          Function = 1,
          Variable = 2,
          Typedef = 4,
          Template = 8,
          NestedType = 16,
          Namespace = 32,
          AllTypes = 0xffffffff
      } memberType;

        MemberInfo() {
          memberType = NotFound;
        }

        TQString memberTypeToString() {
          switch ( memberType ) {
            case Namespace:
            return "namespace";
            case Function:
            return "function";
            case Variable:
            return "variable";
            case NotFound:
            return "not found";
            case Typedef:
            return "typedef";
            case Template:
            return "template-parameter";
            case NestedType:
            return "nested-type";
            default:
            return "unknown";
          };
        }

        typedef TDESharedPtr<SimpleTypeImpl> TypePointer;

        void setBuildInfo( TDESharedPtr<TypeBuildInfo> build ) {
          m_build = build;
        }

	    void setBuilt( const TypePointer& item ) {
		    m_built = item;
	    }
	    
        TypePointer build() {
		  if( m_built ) return m_built;
	      if ( !m_build ) {
            return TypePointer();
		  } else {
            m_built = m_build->buildCached();
            return m_built;
          }
        }

        operator bool() const {
          return memberType != NotFound;
        }

        TQString name;
        LocateResult type;

        ///This member is only filles for variables, typedefs and template-params!
        DeclarationInfo decl;
    private:
	    TypePointer m_built;
    };


    enum LocateMode {
      Normal = 1,
      ExcludeTemplates = 2,
      ExcludeTypedefs = 4,
      ExcludeBases = 8,
      ExcludeParents = 16,
      ExcludeNestedTypes = 32,
      ExcludeNamespaces = 64,
      ForgetModeUpwards = 128,  ///forgets everything, even NoFail, while passing control to the parent
      LocateBase = 4 + 8 + 32 + 64 + 128,  ///searching in the scope visible while the base-declaration of a class
      NoFail = 256,
      TraceAliases = 512,  ///Stores a copy whenever an alias is applied
      OnlyLocalTemplates = 4 + 8 + 16 + 32 + 64 + 256,
      OnlyTemplates = 4 + 8 + 32 + 256
  };

    ///replaces template-parameters from the given structure with their value-types
    TypeDesc replaceTemplateParams( TypeDesc desc, TemplateParamInfo& paramInfo );
    TypeDesc resolveTemplateParams( LocateResult desc, LocateMode mode = Normal );

	//typedef ::LocateResult LocateResult;


    /**By default templates are included while the resolution, so when the type should be addressed from
    outside of the class, ExcludeTemplates should be set as LocateMode, since templates can not be directly accessed    from the outside.
    The resulting type's template-params may not be completely resolved, but can all be resolved locally by that type*/
  LocateResult locateDecType( TypeDesc desc , LocateMode mode = Normal, int dir = 0 , MemberInfo::MemberType typeMask = bitInvert( addFlag( MemberInfo::Variable, MemberInfo::Function ) ) ) {
      TypeDesc td = desc;
      td.clearInstanceInfo();
      LocateResult r = locateType( td, mode, dir, typeMask );
      r.desc() = resolveTemplateParams( r.desc() );
      r->takeInstanceInfo( desc );
      //  r.desc().setPointerDepth( r.desc().pointerDepth() + td.pointerDepth() );
      return r;
    }

    //protected:

  virtual LocateResult locateType( TypeDesc name , LocateMode mode = Normal, int dir = 0 , MemberInfo::MemberType typeMask = bitInvert( addFlag( MemberInfo::Variable, MemberInfo::Function ) ) ) ;

  public:

    LocateResult getFunctionReturnType( TQString functionName, TQValueList<LocateResult> params = TQValueList<LocateResult>() );

    ///Tries to apply the operator and returns the new type. If it fails, it returns an invalid type.
    virtual LocateResult applyOperator( Operator op , TQValueList<LocateResult> params = TQValueList<LocateResult>() );


    /** In case of a class, returns all base-types */
    virtual TQValueList<LocateResult> getBases();

  virtual TQStringList getBaseStrings() {
      return TQStringList();
    };

    ///This pair contains the found type, and additionally the member-information that helped finding the type
    struct TypeOfResult {
      LocateResult type;
      DeclarationInfo decl;

      TypeOfResult( LocateResult t = LocateResult(), DeclarationInfo d = DeclarationInfo() ) : type( t ), decl( d ) {}

      TypeDesc* operator -> () {
        return & type.desc();
      }

      operator TypeDesc() {
        return type;
      }

      ///should be removed
      operator SimpleType() {
        if ( type->resolved() ) {
          return SimpleType( type->resolved() );
        } else {
          return SimpleType();
        }
      }

      operator bool() {
        return ( bool ) type;
      }
    };

  public:

    virtual TypeOfResult typeOf( const TypeDesc& name, MemberInfo::MemberType typ = addFlag( MemberInfo::Function, MemberInfo::Variable ) );


    ///From outside this should only be called for members like functions/variables etc. Classes will not have their bases resolved when acquired using this function.
    virtual MemberInfo findMember( TypeDesc name, MemberInfo::MemberType type = ( MemberInfo::MemberType ) 0xffffffff ) {
      Q_UNUSED( name );
      Q_UNUSED( type );
      MemberInfo mem;
      mem.memberType = MemberInfo::NotFound;
      return mem;
    };

	///Should return all specializations of a specific class-name
	virtual TQValueList<TypePointer> findSpecializations( const TQString& name ) {
		return TQValueList<TypePointer>();
	}

    /**TypeDescs and SimpleTypeImpls usually have a cross-reference, which creates a circular dependency so that they are never freed using TDEShared. This function breaks the loop, and also breaks all other possible dependency-loops. After this function was called, the type still contains its private information, but can not not be used to resolve anything anymore. This function is called automatically while the destruction of SimpleTypeConfiguration */
    virtual void breakReferences();

    ///Returns either itself, or the (namespace-)proxy this type is a slave of.
    TypePointer bigContainer();

    ///Returns the parent, eg. the SimpleType this one is nested in.
    SimpleType parent();

    ///this must be a reference, so the desc can be manipulated in-place from outside
    const TypeDesc& desc();

    TypeDesc& descForEdit();

    ///short version
    TQString fullType() const {
      return m_desc.fullName();
    }

    ///Similar to fullTypeResolved, except that it also shows addition information about template-params
    TQString describeWithParams() ;

    ///returns all information that is available constantly
    TQString describe() const {
      TQString description = m_desc.fullName() + " (" + m_scope.join( "::" ) + ")" + createInfo();
      return description;
    }

    ///this completely evaluates everything
    TQString fullTypeResolved( int depth = 0 );

    ///this completely evaluates everything
    TQString fullTypeResolvedWithScope( int depth = 0 );


    TQString fullTypeUnresolvedWithScope();

	virtual TQValueList<TypePointer> getMemberClasses( const TypeDesc& name ) {
		return TQValueList<TypePointer>();
	}

    ///Returns the include-file-set used for resolving this type
    IncludeFiles getFindIncludeFiles();
	
  private:
    TQStringList m_scope;
    TypePointer m_parent;
    IncludeFiles m_findIncludeFiles; //Set of include-files used for finding this object

  protected:
    SimpleTypeImpl( SimpleTypeImpl* rhs ) : m_masterProxy( rhs->m_masterProxy ), m_resolutionCount( rhs->m_resolutionCount ), m_resolutionFlags( rhs->m_resolutionFlags ), m_scope( rhs->m_scope ), m_parent( rhs->m_parent ), m_findIncludeFiles( rhs->m_findIncludeFiles ), m_desc( rhs->m_desc ) {
      reg();
    }
  
    TypeDesc m_desc;  ///descibes the local type(so next() must be null)

    /** Tries to extract template-parameters from the scope, resets the params-list */
    virtual void checkTemplateParams ();

    void setScope( const TQStringList& scope );

    ///Searches the item IN the bases
    TypeOfResult searchBases ( const TypeDesc& name );

    ///Used to set the include-files that were used to find this type(needed for lazy evaluation of the base-classes)
    void setFindIncludeFiles( const IncludeFiles& files );

		///Should be called within the parent-namespace/class
	virtual void chooseSpecialization( MemberInfo& member );
	
};


class TypeTrace {
    TQValueList<TQPair< SimpleTypeImpl::MemberInfo, TypeDesc> > m_trace;
  public:

    TQValueList<TQPair< SimpleTypeImpl::MemberInfo, TypeDesc> >& trace() {
      return m_trace;
    };

    void prepend( const SimpleTypeImpl::MemberInfo& t, const TypeDesc& tail = TypeDesc() ) {
      m_trace.push_front( TQPair< SimpleTypeImpl::MemberInfo, TypeDesc>( t, tail ) );
    }

	void prepend( const TypeTrace& trace, int indent = 0 ) {
/*		if( indent != 0 ) {
		TQString ind;
			for( int a = 0; a < indent; a++ ) ind += " ";
			for( TQValueList<TQPair< SimpleTypeImpl::MemberInfo, TypeDesc> >::const_iterator it = trace.m_trace.end(); it != trace.m_trace.begin(); ) {
				--it;
				TQPair<SimpleTypeImpl::MemberInfo, TypeDesc> item = *it;
				item.second.prependDecoration( ind );
				m_trace.push_front( item );
			}
 		} else {*/
 		m_trace = trace.m_trace + m_trace;
/* 		}*/
	}
};


#endif 
