/**************************************************************
 * 
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 * 
 *   http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 * 
 *************************************************************/



// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_i18npool.hxx"

#include <com/sun/star/i18n/CharacterIteratorMode.hpp>
#include <breakiterator_ctl.hxx>

#include <string.h>	// for memset

using namespace ::com::sun::star::uno;
using namespace ::com::sun::star::lang;
using namespace ::rtl;

namespace com { namespace sun { namespace star { namespace i18n {

/**
 * Constructor.
 */
BreakIterator_CTL::BreakIterator_CTL() :
    cachedText(),
    nextCellIndex( NULL ),
    previousCellIndex( NULL ),
    cellIndexSize( 512 )
{
	cBreakIterator = "com.sun.star.i18n.BreakIterator_CTL";
	// to improve performance, alloc big enough memory in construct.
	nextCellIndex = (sal_Int32*) calloc(cellIndexSize, sizeof(sal_Int32));
	previousCellIndex = (sal_Int32*) calloc(cellIndexSize, sizeof(sal_Int32));
	memset(nextCellIndex, 0, cellIndexSize * sizeof(sal_Int32));
}

/**
 * Deconstructor.
 */
BreakIterator_CTL::~BreakIterator_CTL()
{
	free(nextCellIndex);
	free(previousCellIndex);
}

sal_Int32 SAL_CALL BreakIterator_CTL::previousCharacters( const OUString& Text,
	sal_Int32 nStartPos, const lang::Locale& rLocale,
	sal_Int16 nCharacterIteratorMode, sal_Int32 nCount, sal_Int32& nDone )
	throw(RuntimeException)
{
	if (nCharacterIteratorMode == CharacterIteratorMode::SKIPCELL ) {
	    nDone = 0;
	    if (nStartPos > 0) { 	// for others to skip cell.
		makeIndex(Text, nStartPos);

		if (nextCellIndex[nStartPos-1] == 0) // not a CTL character
		    return BreakIterator_Unicode::previousCharacters(Text, nStartPos, rLocale,
				nCharacterIteratorMode, nCount, nDone);
		else while (nCount > 0 && nextCellIndex[nStartPos - 1] > 0) {
		    nCount--; nDone++;
		    nStartPos = previousCellIndex[nStartPos - 1];
		}
	    } else 
		nStartPos = 0;
	} else { // for BS to delete one char.
	    nDone = (nStartPos > nCount) ? nCount : nStartPos;
	    nStartPos -= nDone;
	}

	return nStartPos;
}

sal_Int32 SAL_CALL BreakIterator_CTL::nextCharacters(const OUString& Text, 
	sal_Int32 nStartPos, const lang::Locale& rLocale,
	sal_Int16 nCharacterIteratorMode, sal_Int32 nCount, sal_Int32& nDone)
	throw(RuntimeException)
{
	sal_Int32 len = Text.getLength();
	if (nCharacterIteratorMode == CharacterIteratorMode::SKIPCELL ) {
	    nDone = 0;
	    if (nStartPos < len) {
		makeIndex(Text, nStartPos);

		if (nextCellIndex[nStartPos] == 0) // not a CTL character
		    return BreakIterator_Unicode::nextCharacters(Text, nStartPos, rLocale,
				nCharacterIteratorMode, nCount, nDone);
		else while (nCount > 0 && nextCellIndex[nStartPos] > 0) {
		    nCount--; nDone++;
		    nStartPos = nextCellIndex[nStartPos];
		}
	    } else
		nStartPos = len;
	} else {
	    nDone = (len - nStartPos > nCount) ? nCount : len - nStartPos;
	    nStartPos += nDone;
	}

	return nStartPos;
}

// This method should be overwritten by derived language specific class.
void SAL_CALL BreakIterator_CTL::makeIndex(const OUString& /*text*/, sal_Int32 /*pos*/)
	throw(RuntimeException)
{
	throw RuntimeException();
}

// Make sure line is broken on cell boundary if we implement cell iterator.
LineBreakResults SAL_CALL BreakIterator_CTL::getLineBreak(
	const OUString& Text, sal_Int32 nStartPos,
	const lang::Locale& rLocale, sal_Int32 nMinBreakPos,
	const LineBreakHyphenationOptions& hOptions,
	const LineBreakUserOptions& bOptions ) throw(RuntimeException)
{
	LineBreakResults lbr = BreakIterator_Unicode::getLineBreak(Text, nStartPos,
					rLocale, nMinBreakPos, hOptions, bOptions );
    if (lbr.breakIndex < Text.getLength()) {
        makeIndex(Text, lbr.breakIndex);
        lbr.breakIndex = previousCellIndex[ lbr.breakIndex ];
    }
	return lbr;
}

} } } }