/*
 *   This file is part of VBA Express.
 *
 *   Copyright (c) 2005-2006 Achraf cherti <achrafcherti@gmail.com>
 * 
 *   VBA Express 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.
 *
 *   VBA Express 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 VBA Express; if not, write to the Free Software
 *   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 */

/************************************************************
 * Fonctions dynamiques et optimisées pour la gestion
 * de strings en C++.
 *
 * Lisez le fichier AString.cpp pour plus d'informations.
 ************************************************************/

#ifndef _AString_H_
#define _AString_H_

#include <stdio.h>

//#define DEBUG //debug... pour trouver les erreurs

//#define RECALC_LEN  // si definie. A chaque fonction le len sera recalculé (un peu comme dans une cstring)

//#define TEST_ZERO //pour tester si un char *s=NULL est passé à une fonction
//enlever TEST_ZERO fait gagner du temps mais vous impose de ne jamais
//passer un char*=NULL dans les arguments...

typedef bool (AString_cmp_func)(const char *,const char *,size_t);

class AStringList;

class AString
{
 private:
	void _init(); //met les variables à 0
 protected:
	void _realloc(size_t size,bool=false);
	size_t _realloc_size; //le len de la reallocation (non pas le vrai len...)
	char *_ptr;
#ifndef RECALC_LEN
	size_t _len; //seulement quand il n'y a pas recal len
#endif
 public:     // Création/Destruction
// Supprime ce qui reste en mémoire... 
	 void free_extra();
	 size_t extra(); //combien il y a d'extra?

	 //FONCTIONS pour REPLACE
	 //
	 //Quelques fonctions de test
	 //elle RETOURNENT true si s1==s2
	 //(elle font un test sans dépasser len)
	 //static bool cmp       (const char *,const char *, size_t len);
	 static AString_cmp_func cmp;
	 static AString_cmp_func cmp_nocase;

	 // Fonctions like celles du c...
	 static char c_tolower(char);
	 static char c_toupper(char);

	 // Fonction de transformation...
	 AString &transform(char (*)(char));
	 
	 //chercher de carac 0 si rien trouvé.
	 //1ou+ si trouvé
	 //1 = 0 en terme d'index
	size_t instr(char c, size_t pos=0);
	size_t rinstr(char c, size_t pos);
	size_t rinstr(char c);

	 // Remplacement par défaut c'est avec AString::cmp
	 AString &replace(const char *  ,const char *  ,AString_cmp_func(*)=cmp);
	 AString &replace(AString &     ,AString &     ,AString_cmp_func(*)=cmp);
	 AString &replace(const char *  ,AString&      ,AString_cmp_func(*)=cmp);
	 AString &replace(AString &     ,const char *  ,AString_cmp_func(*)=cmp);

	 AString &replace(size_t, const char *  ,const char *  ,AString_cmp_func(*)=cmp);
	 AString &replace(size_t, AString &     ,AString &     ,AString_cmp_func(*)=cmp);
	 AString &replace(size_t, const char *  ,AString&      ,AString_cmp_func(*)=cmp);
	 AString &replace(size_t, AString &     ,const char *  ,AString_cmp_func(*)=cmp);

	AString &replace(char,char); //avec char
	 
	//lecture d'une ligne complète depuis
	//un fichier
	AString &getline(FILE *);

	// Infos
	size_t length();
	size_t size();
	const char *ptr();
	 
	 //retourne l'index de la fin du string...
	 size_t end(); 
	 
	 //majuscule/minuscule
	 AString &ucase(size_t,size_t);
	 AString &ucase(size_t);
	 AString &ucase();
	 AString &lcase(size_t,size_t);
	 AString &lcase(size_t);
	 AString &lcase();

	 // remove
	 AString &remove(size_t);
	 AString &remove(size_t,size_t);

	 //change
	 AString &substr(size_t begin, size_t len); 
	 AString &substr(size_t begin); // de begin à la fin...

	 //trim gauche et droit
	 #define astring_reject " \t\n\v\f"
	 AString &trim(const char  *reject=astring_reject);
	 AString &ltrim(const char *reject=astring_reject);
	 AString &rtrim(const char *reject=astring_reject);
	 #undef astring_reject
	 
	 // Destructeur
     ~AString();

	 // Constructeurs
     AString();
	 AString(AString &);
	 AString(const char *);
	 AString(FILE *);
	 AString(int);
	 AString(long);
	 AString(double);

	 // Les entrées...
	 AString &operator <<(AString &);
	 AString &operator <<(const char *);
	 AString &operator <<(FILE *);
	 AString &operator <<(int);
	 AString &operator <<(long);
	 AString &operator <<(double);
	 
	 // insertion
	 AString &insert(size_t,AString &);
	 AString &insert(size_t,const char *);
	 AString &insert(size_t,FILE *);
	 AString &insert(size_t,int);
	 AString &insert(size_t,long);
	 AString &insert(size_t,double);

	 //conv
	 void operator>>(int&);
	 void operator>>(double&);
	 void operator>>(float&);
	 void operator>>(long&);
	 int  operator>>(FILE *);

	 // ==
	 bool operator==(AString &);
	 bool operator==(const char *);
	 bool operator!=(AString &);
	 bool operator!=(const char *);

     // =
	AString &operator=(AString &);
	AString &operator=(const char *);
	AString &operator=(int);
	AString &operator=(double);
	AString &operator=(FILE *);
	AString &operator=(long);

	 // *=
	 AString &operator*=(size_t);

	 // []
	 char operator[] (size_t); //attention a ne pas dépasser []

	 // Joindre une AStringList (en effacant l'ancien contenu AString)
	 AString &join(AStringList &, const char * = " ");
	 AString &join(AStringList &, AString &);
	 AString &operator=(AStringList &); //joindre avec espaces...
	 
	 // Ajouter AStringList dans une chaine
	 AString &join_cat(AStringList &, const char * = " ");
	 AString &join_cat(AStringList &, AString &);
	 AString &operator<<(AStringList &);

	 // Pour splitter ce string dans un AStringList
	 AString &split      (AStringList &,const char *);
	 AString &split      (AStringList &,AString &);
	 AString &split_cat  (AStringList &,const char *);
	 AString &split_cat  (AStringList &,AString &);

	 // Push dans une AStringList
	 void operator>>(AStringList &);

	 // Fonctions utiles
	 AString &chomp(); // del \n final
	 char chop();  // del char final puis ret
};

class AStringList
{
	protected:
		AString **_list;
		size_t  _size;
		void _realloc(size_t);
		size_t _realloc_size;
	public:
		AStringList();
		AStringList(AStringList &);
		~AStringList();

		//supprime ce qui reste en mémoire :-)
		void free_extra();

		//infos
		size_t size();
		AString &operator[] (size_t);

		//pop
		void operator>>(AString &);

		//push
		AStringList &push(AStringList &);
		AStringList &push(AString &);
		AStringList &push(const char *);
		AStringList &operator<<(AStringList &);
		AStringList &operator<<(AString &);
		AStringList &operator<<(const char *);

		//assignation
		AStringList &copy(AStringList &);

		//shift
		AStringList &shift(AStringList &);
		AStringList &shift(AString &);
		AStringList &shift(const char *);

		//insert
		AStringList &insert(size_t,AStringList &);
		AStringList &insert(size_t,AString &);
		AStringList &insert(size_t,const char *);

		//remove
		AStringList &remove(size_t);
		AStringList &remove(size_t,size_t);

		// Suppr tout!
		AStringList &clear();

		//échange
		AStringList &swap(size_t,size_t);

		//move
		AStringList &move(size_t,size_t);

		//dupliquer la liste
		void operator*=(size_t); 

		// IO dans un fichier...
		AStringList &operator>>(FILE *);
		AStringList &operator<<(FILE *);
		bool load(const char *);
		bool save(const char *);
		bool load(AString &);
		bool save(AString &);
};

#ifdef DEBUG
extern int AString_num_alloc;
extern int AStringList_num_alloc;
#endif

#endif

