/* ====================================================================
 * Copyright (c) 2003-2006, Martin Hauner
 *                          http://subcommander.tigris.org
 *
 * Subcommander is licensed as described in the file doc/COPYING, which
 * you should have received as part of this distribution.
 * ====================================================================
 */

// sc
#include "Tab.h"
#include "util/utf8.h"


/**
 * \brief construct a Tab object. 
 *
 * \param tabWidth use tabwidth spaces for a single tab in the column
 * calculations.
 */

Tab::Tab( unsigned int tabWidth )
: _tabwidth(tabWidth)
{
}


/**
 * \brief calc the number of columns in a string.
 * A CRLF counts as a single column.
 *
 * \param s an utf-8 encoded 0 terminated string.
 */

unsigned int Tab::calcColumns( const char* s )
{
  unsigned int chars = 0;

  if( ! s )
  {
    return 0;
  }

  while( *s )
  {
    if( *s == '\t' && (chars % _tabwidth == 0) )
    {
      chars += _tabwidth;
    }
    else if( *s == '\r' || *s == '\n' )
    {
      // on any line end marker we are done
      break;
    }
    else
    {
      chars += 1;
    }

    s = utf8::next8( s );
  }

  return chars;
}


/**
 * \brief calc next column, on tab jump tabwidth.
 * A CRLF counts as a single column.
 *
 * \param s    an utf-8 encoded 0 terminated string.
 * \param pos  current column position.
 */

int Tab::calcColumnForNextChar( const char* s, int pos )
{
  int col = 0;

  if( ! s )
  {
    return pos;
  }

  while( *s && col <= pos )
  {
    if( *s == '\t' && (col % _tabwidth == 0) )
    {
      col += _tabwidth;
    }
    else 
    {
      col += 1;
      
      // on any line end marker we are done
      // next col is after end of line
      if( *s == '\r' || *s == '\n' )
      {
        break;
      }
    }

    s = utf8::next8( s );
  }

  return col;
}


/**
 * \brief calc prev column, on tab jump tabwidth.
 * A CRLF counts as a single column.
 *
 * \param s    an utf-8 encoded 0 terminated string.
 * \param pos  current column position.
 */

int Tab::calcColumnForPrevChar( const char* s, int pos )
{
  int col = 0;

  if( ! s )
  {
    return pos;
  }

  while( *s && col < pos )
  {
    int plus = 0;

    if( *s == '\t' && (col % _tabwidth == 0) )
    {
      plus = _tabwidth;
    }
    else if( *s == '\r' || *s == '\n' )
    {
      // shouldn't happen
    }
    else
    {
      plus = 1;
    }

    if( col + plus >= pos )
    {
      break;
    }

    col += plus;

    s = utf8::next8( s );
  }

  return col;
}

/**
 * \brief calc the character offset for the character at the given column.
 * A CRLF counts as a single column.
 *
 * \param s   an utf-8 encoded 0 terminated string.
 * \param col the column for which we calculate the character offset.
 */

int Tab::calcCharOffsetForColumn( const char* s, int col )
{
  int pos = 0;
  int chr = 0;

  if( ! s )
  {
    return pos;
  }

  while( *s && pos < col )
  {
    if( *s == '\t' && (pos % _tabwidth == 0) )
    {
      pos += _tabwidth;
    }
    else if( *s == '\r' || *s == '\n' )
    {
      // shouldn't happen
      break;
    }
    else
    {
      pos += 1;
    }

    s = utf8::next8( s );
    chr++;
  }

  return chr;
}

/**
 * \brief calc the nearest column position for the given column.
 * This is used if you click into the space of a tab to position
 * a cursor at the column where the tab begins or the tab ends.
 *
 * \param s   an utf-8 encoded 0 terminated string.
 * \param col the column for which we calculate the new column.
 */

int Tab::calcColumnForColumn( const char* s, int col )
{
  int ncol = 0;

  if( ! s )
  {
    return 0;
  }

  while( *s && ncol <= col )
  {
    int add = 0;

    if( *s == '\t' && (ncol % _tabwidth == 0) )
    {
      add = _tabwidth;
    }
    else if( *s == '\r' || *s == '\n' )
    {
      // count CRLF as one column
    }
    else
    {
      add = 1;
    }

    if( ncol + add > col )
    {
      break;
    }

    ncol += add;
    s = utf8::next8( s );
  }

  return ncol;
}


