Fresco/Babylon/include/Babylon/internal Blocks.hh,NONE,1.1 Boundaries.hh,NONE,1.1 Dictionary.hh,NONE,1.1 traits.hh,NONE,1.1 utfstrings.hh,NONE,1.1 utils.hh,NONE,1.1

Tobias Hunger <[email protected]> Fri, 01 Aug 2003 11:47:14 -0500
Newsgroups gmane.comp.video.fresco.cvs
Message-ID <[email protected]>
Update of /cvs/fresco/Fresco/Babylon/include/Babylon/internal
In directory purcel:/tmp/cvs-serv24256/Babylon/include/Babylon/internal

Added Files:
	Blocks.hh Boundaries.hh Dictionary.hh traits.hh utfstrings.hh 
	utils.hh 
Log Message:
Babylon work over:
 * Use iconv to convert characters to/from Babylon
 * Updtae to Unicode Version 4.0
 * Added unit tests (some fail for now, still need to work on that)

 * Removed the VisualTextBuffer from the CommandKit: I still like the idea,
   unfortunately it won't work out in the real world:-|

 * Updated code to the changed Babylon interfaces whereever needed.


--- NEW FILE: Blocks.hh ---
/*$Id: Blocks.hh,v 1.1 2003/08/01 16:47:11 tobias Exp $
 *
 * This source file is a part of the Fresco Project.
 * Copyright (C) 1999-2003 Tobias Hunger <[email protected]>
 * http://www.fresco.org
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library 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
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public
 * License along with this library; if not, write to the
 * Free Software Foundation, Inc., 675 Mass Ave, Cambridge,
 * MA 02139, USA.
 */

#ifndef _Babylon_internal_Blocks_hh_
#define _Babylon_internal_Blocks_hh_

#include <Babylon/internal/utfstrings.hh>
#include <Prague/Sys/Plugin.hh>

namespace Babylon {

  class Block {
      // This class is subclassed by plugin libraries.
      // No method bodies here!!
      
      // These Blocks are build for speed, not safety!
      // The Dictionary has to make sure that it is
      // asking the right block about defined properties.
      
      // It can do so by calling the appropriate is_*
      
  public:
      Block() { }
      virtual ~Block() { }
      virtual void clean() { }
      virtual bool is_undef_block() const = 0; // returns 1 if this
	                                       // block is meant to handle
	                                       // all undefined characters
	                                       // 
	                                       // The first undef_block
	                                       // found will be used!
	
      // Query Functions:
      virtual bool is_defined(const UCS4)  const = 0;
      virtual UCS4 uppercase(const UCS4) const = 0;
      virtual UCS4 lowercase(const UCS4) const = 0;
      virtual UCS4 titlecase(const UCS4) const = 0;
      
      virtual float numeric_value(const UCS4) const = 0;
      virtual bool is_Numeric(const UCS4) const = 0;
      virtual int dec_digit_value(const UCS4) const = 0;
      virtual bool is_Decimal_Digit(const UCS4) const = 0;
      virtual int digit_value(const UCS4) const = 0;
      virtual bool is_Digit(const UCS4) const = 0;
      
      virtual std::string blockname(const UCS4) const = 0;
      virtual Gen_Cat category(const UCS4) const = 0;
      virtual Can_Comb_Class comb_class(const UCS4) const = 0;
      virtual Bidir_Props bidir_props(const UCS4) const = 0;
      virtual Char_Decomp decomp_type(const UCS4) const = 0;
      virtual UTF32_string decompose(const UCS4) const = 0;
      virtual bool exclude_from_composition(const UCS4 uc) const = 0;
      virtual UCS4 compose(const UCS4, const UCS4) = 0;
      virtual bool must_mirror(const UCS4) const = 0;
      virtual EA_Width EA_width(const UCS4) const = 0;
      virtual Line_Break linebreak(const UCS4) const = 0;
      
      // Properties:
      virtual bool is_White_Space(const UCS4) const = 0;
      virtual bool is_Bidi_Control(const UCS4) const = 0;
      virtual bool is_Join_Control(const UCS4) const = 0;
      virtual bool is_Dash(const UCS4) const = 0;
      virtual bool is_Hyphen(const UCS4) const = 0;
      virtual bool is_Quotation_Mark(const UCS4) const = 0;
      virtual bool is_Terminal_Punctuation(const UCS4) const = 0;
      virtual bool is_Other_Math(const UCS4) const = 0;
      virtual bool is_Hex_Digit(const UCS4) const = 0;
      virtual bool is_ASCII_Hex_Digit(const UCS4) const = 0;
      virtual bool is_Other_Alphabetic(const UCS4) const = 0;
      virtual bool is_Ideographic(const UCS4) const = 0;
      virtual bool is_Diacritic(const UCS4) const = 0;
      virtual bool is_Extender(const UCS4) const = 0;
      virtual bool is_Other_Uppercase(const UCS4) const = 0;
      virtual bool is_Other_Lowercase(const UCS4) const = 0;
      virtual bool is_Noncharacter_Code_Point(const UCS4) const = 0;
      virtual bool is_Other_Grapheme_Extend(const UCS4) const = 0;
      virtual bool is_Grapheme_Link(const UCS4) const = 0;
      virtual bool is_IDS_Binary_Operator(const UCS4) const = 0;
      virtual bool is_IDS_Trinary_Operator(const UCS4) const = 0;
      virtual bool is_Radical(const UCS4) const = 0;
      virtual bool is_Unified_Ideograph(const UCS4) const = 0;
      virtual bool is_Other_Default_Ignorable_Code_Point(const UCS4) const = 0;
      virtual bool is_Deprecated(const UCS4) const = 0;
      virtual bool is_Soft_Dotted(const UCS4) const = 0;
      virtual bool is_Logical_Order_Exception(const UCS4) const = 0;
      virtual bool is_Other_ID_Start(const UCS4) const = 0;
      
      virtual UCS4 first_letter() const = 0;
      virtual UCS4 last_letter() const = 0;
  protected:
      
  private:
  }; // class Block
    
}; // namespace Babylon

#endif

--- NEW FILE: Boundaries.hh ---
/*$Id: Boundaries.hh,v 1.1 2003/08/01 16:47:11 tobias Exp $
 *
 * This source file is a part of the Fresco Project.
 * Copyright (C) 1999-2003 Tobias Hunger <[email protected]>
 * http://www.fresco.org
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library 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
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public
 * License along with this library; if not, write to the
 * Free Software Foundation, Inc., 675 Mass Ave, Cambridge,
 * MA 02139, USA.
 */

#ifndef _Babylon_internal_Boundaries_hh_
#define _Babylon_internal_Boundaries_hh_

namespace Babylon {

  class Char;

  bool is_graphem_cluster_boundary(const Char &, const Char &);
  bool is_word_boundary(const Char &, const Char &);
  bool is_sentense_boundary(const Char &, const Char &);
    
}; // namespace Babylon

#endif

--- NEW FILE: Dictionary.hh ---
/*$Id: Dictionary.hh,v 1.1 2003/08/01 16:47:11 tobias Exp $
 *
 * This source file is a part of the Fresco Project.
 * Copyright (C) 1999-2003 Tobias Hunger <[email protected]>
 * http://www.fresco.org
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library 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
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public
 * License along with this library; if not, write to the
 * Free Software Foundation, Inc., 675 Mass Ave, Cambridge,
 * MA 02139, USA.
 */

#ifndef _Babylon_internal_Dictionary_hh_
#define _Babylon_internal_Dictionary_hh_

#include <Babylon/exceptions.hh>
#include <Babylon/internal/utfstrings.hh>

#include <Prague/Sys/Plugin.hh>
#include <Prague/Sys/Thread.hh>
#include <Prague/Sys/Path.hh>

namespace Babylon {
  class Block;

  //. Stores character data.
  class Dictionary {

      struct Dict_Guard
      {
	  ~Dict_Guard() { delete Dictionary::my_dictionary; }
      };
      friend struct Dict_Guard;
      
  public:
      //. Scans a directory for modules.
      void update(const std::string &)
	  throw (std::runtime_error, Block_Error);
      
      //. Finds the current dictionary.
      //. If no dictionary exists it will create one.
      static Dictionary * instance();
      
      // Queries for the datastructures stored in the Dictionary:
      
      //. Returns the first letter of the block (aka script)
      //. the given character belongs to. It returns
      //. UC_MAX_DEFINED if the character does not belong
      //. to a block.
      UCS4 first_letter_of_block(const UCS4) const throw ();
      
      //. Returns the last letter of the block (aka script)
      //. the given character belongs to. It returns
      //. UC_MAX_DEFINED if the character does not belong
      //. to a block
      UCS4 last_letter_of_block(const UCS4) const throw ();
      
      //. Returns the first letter of the next block (aka script)
      //. defined block after the given character.
      //. It returns UC_MAX_DEFINED if there is no block after
      //. the character.
      UCS4 start_of_next_block(const UCS4) const throw();
      
      // Query functions:
      bool is_defined(const UCS4 uc) const throw (Block_Error);    
      UCS4 uppercase(const UCS4 uc) const throw (Block_Error);
      UCS4 lowercase(const UCS4 uc) const throw (Block_Error);
      UCS4 titlecase(const UCS4 uc) const throw (Block_Error);
      
      float numeric_value(const UCS4 uc) const
	  throw (Undefined_Property, Block_Error);
      bool is_Numeric(const UCS4 uc) const
	  throw (Block_Error);
      int dec_digit_value(const UCS4 uc) const
	  throw (Undefined_Property, Block_Error);
      bool is_Decimal_Digit(const UCS4 uc) const
	  throw (Block_Error);
      int digit_value(const UCS4 uc) const
	  throw (Undefined_Property, Block_Error);
      bool is_Digit(const UCS4 uc) const
	  throw (Block_Error);
      
      std::string blockname(const UCS4 uc) const
	  throw (Block_Error);
      
      Gen_Cat category(const UCS4) const
	  throw (Undefined_Property, Block_Error);
      Can_Comb_Class comb_class(const UCS4) const
	  throw (Undefined_Property, Block_Error);
      Bidir_Props bidir_props(const UCS4) const
	  throw (Undefined_Property, Block_Error);
      Char_Decomp decomp_type(const UCS4) const
	  throw (Undefined_Property, Block_Error);
      UTF32_string decompose(const UCS4) const
	  throw (Block_Error);
      
      UTF32_string recursive_decompose(const bool compat, const UCS4 uc) const
	  throw (Block_Error);
      
      bool exclude_from_composition(const UCS4) const throw (Block_Error);
      UCS4 compose(const UCS4 starter, const UCS4 last) const
	  throw (Block_Error);
      
      bool must_mirror(const UCS4 uc) const throw (Block_Error);
      
      EA_Width EA_width(const UCS4 uc) const throw (Block_Error);
      Line_Break linebreak(const UCS4 uc) const throw (Block_Error);
      
      // Properties:
      bool is_White_Space(const UCS4) const throw (Block_Error);
      bool is_Bidi_Control(const UCS4) const throw (Block_Error);
      bool is_Join_Control(const UCS4) const throw (Block_Error);
      bool is_Dash(const UCS4) const throw (Block_Error);
      bool is_Hyphen(const UCS4) const throw (Block_Error);
      bool is_Quotation_Mark(const UCS4) const throw (Block_Error);
      bool is_Terminal_Punctuation(const UCS4) const throw (Block_Error);
      bool is_Other_Math(const UCS4) const throw (Block_Error);
      bool is_Hex_Digit(const UCS4) const throw (Block_Error);
      bool is_ASCII_Hex_Digit(const UCS4) const throw (Block_Error);
      bool is_Other_Alphabetic(const UCS4) const throw (Block_Error);
      bool is_Ideographic(const UCS4) const throw (Block_Error);
      bool is_Diacritic(const UCS4) const throw (Block_Error);
      bool is_Extender(const UCS4) const throw (Block_Error);
      bool is_Other_Lowercase(const UCS4) const throw (Block_Error);
      bool is_Other_Uppercase(const UCS4) const throw (Block_Error);
      bool is_Noncharacter_Code_Point(const UCS4) const throw (Block_Error);
      bool is_Other_Grapheme_Extend(const UCS4) const throw (Block_Error);
      bool is_Grapheme_Link(const UCS4) const throw (Block_Error);
      bool is_IDS_Binary_Operator(const UCS4) const throw (Block_Error);
      bool is_IDS_Trinary_Operator(const UCS4) const throw (Block_Error);
      bool is_Radical(const UCS4) const throw (Block_Error);
      bool is_Unified_Ideograph(const UCS4) const throw (Block_Error);
      bool is_Other_Default_Ignorable_Code_Point(const UCS4) const
	  throw (Block_Error);
      bool is_Deprecated(const UCS4) const throw (Block_Error);
      bool is_Soft_Dotted(const UCS4) const throw (Block_Error);
      bool is_Logical_Order_Exception(const UCS4) const throw (Block_Error);
      bool is_Other_ID_Start(const UCS4) const throw (Block_Error);

      // Derived Properties:
      bool is_Math(const UCS4) const throw (Block_Error);
      bool is_Alphabetic(const UCS4) const throw (Block_Error);
      bool is_Lowercase(const UCS4) const throw (Block_Error);
      bool is_Uppercase(const UCS4) const throw (Block_Error);
      bool is_ID_Start(const UCS4) const throw (Block_Error);
      bool is_ID_Continue(const UCS4) const throw (Block_Error);
      bool is_XID_Start(const UCS4) const throw (Block_Error);
      bool is_XID_Continue(const UCS4) const throw (Block_Error);
      bool is_Default_Ignorable_Code_Point(const UCS4) const
	  throw (Block_Error);
      bool is_Grapheme_Extend(const UCS4) const throw (Block_Error);
      bool is_Grapheme_Base(const UCS4) const throw (Block_Error);
      bool is_FC_NFKC_Closure(const UCS4) const throw (Block_Error);
      bool is_Full_Composition_Exclusion(const UCS4) const
	  throw (Block_Error);
      bool is_NFD_QuickCheck(const UCS4) const throw (Block_Error);
      bool is_NFC_QuickCheck(const UCS4) const throw (Block_Error);
      bool is_NFKD_QuickCheck(const UCS4) const throw (Block_Error);
      bool is_NFKC_QuickCheck(const UCS4) const throw (Block_Error);
      bool is_Expands_On_NFD(const UCS4) const throw (Block_Error);
      bool is_Expands_On_NFC(const UCS4) const throw (Block_Error);
      bool is_Expands_On_NFKD(const UCS4) const throw (Block_Error);
      bool is_Expands_On_NFKC(const UCS4) const throw (Block_Error);

      // Further Properties:
      bool is_Space(const UCS4) const throw (Block_Error);
      bool is_Punctuation(const UCS4) const throw (Block_Error);
      bool is_Line_Separator(const UCS4) const throw (Block_Error);
      bool is_Paragraph_Separator(const UCS4) const throw (Block_Error);
      bool is_Currency_Symbol(const UCS4) const throw (Block_Error);
      bool is_Bidi_Left_to_Right(const UCS4) const throw (Block_Error);
      bool is_Bidi_European_Digit(const UCS4) const throw (Block_Error);
      bool is_Bidi_Eur_Num_Separator(const UCS4) const throw (Block_Error);
      bool is_Bidi_Eur_Num_Terminator(const UCS4) const throw (Block_Error);
      bool is_Bidi_Arabic_Digit(const UCS4) const throw (Block_Error);
      bool is_Bidi_Common_Separator(const UCS4) const throw (Block_Error);
      bool is_Bidi_Block_Separator(const UCS4) const throw (Block_Error);
      bool is_Bidi_Segment_Separator(const UCS4) const throw (Block_Error);
      bool is_Bidi_Whitespace(const UCS4) const throw (Block_Error);
      bool is_Bidi_Non_spacing_Mark(const UCS4) const throw (Block_Error);
      bool is_Bidi_Boundary_Neutral(const UCS4) const throw (Block_Error);
      bool is_Bidi_PDF(const UCS4) const throw (Block_Error);
      bool is_Bidi_Embedding_or_Override(const UCS4) const
	  throw (Block_Error);
      bool is_Bidi_Other_Neutral(const UCS4) const throw (Block_Error);
      bool is_Virama(const UCS4) const throw (Block_Error);
      bool is_Printable(const UCS4) const throw (Block_Error);
      bool is_Titlecase(const UCS4) const throw (Block_Error);
      bool is_Private_Use(const UCS4) const throw (Block_Error);

    private:

      struct Data
      {
	  UCS4 my_start;
	  UCS4 my_end;
	  std::string my_file;
	  int operator < (const Data & data) const
	  {
	      return my_start < data.my_start;
	  }
	  bool my_can_remove;
	  Prague::Plugin<Babylon::Block> * my_block;
	  
	  Data(UCS4 start, UCS4 end)
	  {
	      my_start = start;
	      my_end = end;
	      my_file = "";
	      my_can_remove = 0;
	      my_block = 0;
	  }
      }; // struct Data

      class DataLess {
      public:
	  bool operator() (const Data & d1, const Data & d2)
	  {
	      return d1.my_end < d2.my_start;
	  }
      }; // class DataLess
      
      Prague::Plugin<Babylon::Block> * my_undef_block;
      
      Babylon::Block * find_char(const UCS4) const throw (Block_Error);
      
      Dictionary();
      Dictionary(const Dictionary &) {}
      ~Dictionary();
      void clean();
      
      static Dictionary * my_dictionary;
      static Dict_Guard my_guard;
      static Prague::Mutex my_singleton_mutex;
      
      mutable std::vector<Data> my_data;
      
      mutable Prague::RWLock my_rw_lock;
      
  }; // class Dictionary
    
}; // namespace Babylon

#endif

--- NEW FILE: traits.hh ---
/*$Id: traits.hh,v 1.1 2003/08/01 16:47:11 tobias Exp $
 *
 * This source file is a part of the Fresco Project.
 * Copyright (C) 1999-2003 Tobias Hunger <[email protected]>
 * http://www.fresco.org
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library 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
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public
 * License along with this library; if not, write to the
 * Free Software Foundation, Inc., 675 Mass Ave, Cambridge,
 * MA 02139, USA.
 */

#ifndef _Babylon_internal_traits_hh
#define _Babylon_internal_traits_hh

#if __GNUC__ >= 3

#include <Babylon/Char.hh>

namespace std {

// char_traits

template<>
struct char_traits< ::Babylon::Char >
{
    typedef ::Babylon::Char char_type;

    static void assign(char_type& c1, const char_type& c2) { c1 = c2; }

    // integer repressentation of characters
    typedef ::Babylon::UCS4 int_type;

    static char_type
    to_char_type(const int_type& i) { return ::Babylon::Char(i); }
  
    static int_type
    to_int_type(const char_type& c) { return(c.value()); }

    static bool
    eq_int_type(const int_type& i1, const int_type& i2) { return(i1 == i2); }

    // char_type comparison
    static bool
    eq(const char_type& c1, const char_type& c2) { return(c1 == c2); }

    static bool
    lt(const char_type& c1, const char_type& c2) { return(c1 < c2); }

    // operations on s[n] arrays
    static char_type*
    move(char_type* s, const char_type * s2, size_t n);

    static char_type*
    copy(char_type* s, const char_type * s2, size_t n);

    static char_type*
    assign(char_type* s, size_t n, char_type a);

    static int
    compare(const char_type * s, const char_type * s2, size_t n);

    static size_t length(const char_type * s);

    static const char_type *
    find(const char_type * s, size_t n, const char_type& c);

    // I/O related:
    typedef size_t pos_type;
    typedef size_t off_type;
    typedef mbstate_t state_type;

    static int_type eof() { return(::Babylon::UC_NULL); }
    static int_type not_eof(const int_type &);
    static state_type get_state(pos_type p) {} // FIXME: What should go here?
};

}; // namespace std

#endif // __GNUC__ >= 3

#endif

--- NEW FILE: utfstrings.hh ---
/*$Id: utfstrings.hh,v 1.1 2003/08/01 16:47:11 tobias Exp $
 *
 * This source file is a part of the Fresco Project.
 * Copyright (C) 1999-2003 Tobias Hunger <[email protected]>
 * http://www.fresco.org
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library 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
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public
 * License along with this library; if not, write to the
 * Free Software Foundation, Inc., 675 Mass Ave, Cambridge,
 * MA 02139, USA.
 */

#ifndef _Babylon_internal_utfstrings_hh
#define _Babylon_internal_utfstrings_hh

/* String class
 * This class stores and manipulates strings of characters defined 
 * according to ISO10646. 
 */

#include <Babylon/defs.hh>
#include <string>
#include <Babylon/String.hh>

namespace Babylon {

  class String;

  typedef std::basic_string<UCS2> UTF16_string;
  typedef std::basic_string<UCS4> UTF32_string;
  typedef std::string UTF8_string;

  // This function is necessary to hide UTF32_string,
  // which is used internally, from the user and the API he
  // sees in the Char and String classes.
  inline void get_from_UTF32(UTF32_string in, String & out)
  {
      out.resize(in.length());
      Babylon::UTF32_string::const_iterator j = in.begin();
      for (Babylon::String::iterator i = out.begin();
	   i != out.end();
	   ++i, ++j) i->operator=(*j);
  }


  /*
  class Char_Mapping : public std::basic_string<size_t>
  {
  public:
      Char_Mapping(size_t start, size_t length)
      {
	  resize(length);

	  for (size_t i = 0; i < length; ++i)
	      (*this)[i] = i + start;
      }

      Char_Mapping() {}
  };
  */
};

#endif

--- NEW FILE: utils.hh ---
/*$Id: utils.hh,v 1.1 2003/08/01 16:47:11 tobias Exp $
 *
 * This source file is a part of the Fresco Project.
 * Copyright (C) 1999-2003 Tobias Hunger <[email protected]>
 * http://www.fresco.org
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library 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
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public
 * License along with this library; if not, write to the
 * Free Software Foundation, Inc., 675 Mass Ave, Cambridge,
 * MA 02139, USA.
 */

#ifndef _Babylon_internal_utils_hh
#define _Babylon_internal_utils_hh

// ---------------------------------------------------------------------------
// Helperfunctions for Bidir:
// ---------------------------------------------------------------------------

namespace Babylon {

  inline bool bidir_is_strong(const Babylon::Bidir_Props & p)
  {
      return (p & Babylon::BIDIR_MASK_STRONG);
  }

  inline bool bidir_is_neutral(const Babylon::Bidir_Props & p)
  {
      return (p & Babylon::BIDIR_MASK_NEUTRAL);
  }

  inline bool bidir_is_explicit_or_bn(const Babylon::Bidir_Props & p)
  {
      return (p & (BIDIR_MASK_EXPLICIT | BIDIR_MASK_BN));
  }

  inline bool bidir_is_letter(const Babylon::Bidir_Props & p)
  {
      return (p & Babylon::BIDIR_MASK_LETTER);
  }

  inline bool bidir_is_number(const Babylon::Bidir_Props & p)
  {
      return (p & Babylon::BIDIR_MASK_NUMBER);
  }

  inline bool bidir_is_override(const Babylon::Bidir_Props & p)
  {
      return (p & Babylon::BIDIR_MASK_OVERRIDE);
  }

  inline bool bidir_is_ES_or_CS(const Babylon::Bidir_Props & p)
  {
      return (p & (Babylon::BIDIR_MASK_ES | Babylon::BIDIR_MASK_CS));
  }

  inline bool bidir_is_separator(const Babylon::Bidir_Props & p)
  {
      return (p & Babylon::BIDIR_MASK_SEPARATOR);
  }

  inline Babylon::Bidir_Props
  bidir_change_number_to_RTL(const Babylon::Bidir_Props &p)
  {
      return (bidir_is_number(p) ? Babylon::BIDIR_R : p);
  }

  inline bool
  bidir_is_explicit_or_separator_or_BN_or_WS(const Babylon::Bidir_Props & p)
  {
      return (p & (Babylon::BIDIR_MASK_EXPLICIT |
		   Babylon::BIDIR_MASK_SEPARATOR |
		   Babylon::BIDIR_MASK_BN |
		   Babylon::BIDIR_MASK_WS));
  }

  inline bool
  bidir_is_number_separator_or_terminator(const Babylon::Bidir_Props & p)
  {
      return (p & Babylon::BIDIR_MASK_NUMSEPTER);
  }

  inline bool bidir_is_PDF(const Babylon::Bidir_Props & p)
  {
      return (p == BIDIR_PDF);
  }

  inline unsigned char bidir_to_level(const Babylon::Bidir_Props&  p)
  {
      return (p & 1);
  }

  inline Babylon::Bidir_Props level_to_bidir(const unsigned char lev)
  {
      return (Babylon::Bidir_Props(Babylon::BIDIR_L | (lev & 1)));
  }

  inline Babylon::Bidir_Props
  bidir_explicit_to_override_dir(const Babylon::Bidir_Props & p)
  {
      return (bidir_is_override(p) ?
	      level_to_bidir(bidir_to_level(p)) : 
	      BIDIR_ON);
  }

  inline bool compact(const Babylon::Embedding_Level & a,
		      const Babylon::Embedding_Level & b)
  {
      return (a.bidir_type == b.bidir_type && a.level == b.level);
  }

  inline bool compact_neutrals(const Babylon::Embedding_Level & a,
			       const Babylon::Embedding_Level & b)
  {
      return (a.level == b.level &&
	      (a.bidir_type == b.bidir_type ||
	       bidir_is_neutral(a.bidir_type) &&
	       bidir_is_neutral(b.bidir_type)));
  }

  inline Babylon::Bidir_Props change_number_to_rtl(Babylon::Bidir_Props p)
  {
      return (bidir_is_number(p) ? Babylon::BIDIR_R : p);
  }


  Embedding_Levels::iterator
  compact(const Embedding_Levels::iterator & start,
	  const Embedding_Levels::iterator & end)
  {
      Prague::Trace trace("Babylon::compact(...)");
      if (start == end) return(end);
      
      Embedding_Levels::iterator last_used = start;
      Embedding_Levels::iterator current = start;
      ++current;
      
      while(current != end)
      {
	  if (last_used->level == current->level &&
	      last_used->bidir_type == current->bidir_type)
	      last_used->increment_length(current->length());
	  else
	  {
	      ++last_used;
	      std::iter_swap(last_used, current);
	  }
	  ++current;
      }
      
      return (++last_used);
  }

  Embedding_Levels::iterator
  compact_neutrals(const Embedding_Levels::iterator & start,
		   const Embedding_Levels::iterator & end)
  {
      Prague::Trace trace("Babylon::compact_neutrals(...)");
      if (start == end) return (end);
      
      Embedding_Levels::iterator last_used = start;
      Embedding_Levels::iterator current = start;
      ++current;
      
      while(current != end)
      {
	  if (last_used->level == current->level &&
	      (last_used->bidir_type == current->bidir_type ||
	       bidir_is_neutral(last_used->bidir_type) &&
	       bidir_is_neutral(current->bidir_type)))
	      last_used->increment_length(current->length());
	  else
	  {
	      ++last_used;
	      std::iter_swap(last_used, current);
	  }
	  ++current;
      }

      return(++last_used);
  }

  Embedding_Levels
  override_lists(const Embedding_Levels & base,
		 const Embedding_Levels & over)
  {
      Prague::Trace trace("Babylon::override_lists(...)");
      if (base.empty()) return (over);
      if (over.empty()) return (base);
      
      Embedding_Levels::const_iterator over_it = over.begin();
      Embedding_Levels::const_iterator base_it = base.begin();
      
      Embedding_Levels result;
      
      while(!(over_it == over.end() && base_it == base.end()))
      {
	  // One list is empty, copy the other over:
	  if (over_it == over.end())
	  {
	      // copy base
	      std::copy(base_it, base.end(),
			std::back_inserter(result));
	      base_it = base.end();
	      continue;
	  }
	  
	  if (base_it == base.end())
	  {
	      // copy over
	      std::copy(over_it, over.end(),
			std::back_inserter(result));
	      over_it = over.end();
	      continue;
	  }
	  
	  // skip invalid entries
	  if (over_it->length() == 0)
	  {
	      ++over_it;
	      continue;
	  }
	  
	  if (base_it->length() == 0)
	  {
	      ++base_it;
	      continue;
	  }
	
	  size_t max_current = base_it->ends_at();
	  
	  // copying base:
	  if (max_current < over_it->starts_at())
	  {
	      result.push_back(*base_it);
	      ++base_it;
	      continue;
	  }
	  
	  // inserting over_it into base_it
	  if (max_current >= over_it->starts_at())
	  {
	      Babylon::Embedding_Level current = *base_it;
	      
	      // Insert first part of base if not empty:
	      current.length(over_it->starts_at() - current.starts_at());
	      if (current.length() != 0)
		  // current.length can't become < 0 as
		  // max_current >= over_it.start
		  result.push_back(current);
	      
	      // Insert over_it (we allways need to do this!)
	      result.push_back(*over_it);
	      
	      // over_it reaches into the next base_it:
	      while (base_it != base.end() &&
		     base_it->ends_at() < over_it->ends_at())
		  ++base_it;

	      if (base_it == base.end()) continue;
	      
	      current = *base_it;
	      current.length(current.ends_at() - over_it->ends_at());
	      current.starts_at(over_it->ends_at() + 1);
	      ++base_it;
	      ++over_it;
	      continue;
	  }
      } // while
      
      return (result);
  }

}; // namespace Babylon

#endif