/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * Copyright 2000, 2010 Oracle and/or its affiliates.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * This file is part of OpenOffice.org.
 *
 * OpenOffice.org is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * OpenOffice.org 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 Lesser General Public License version 3 for more details
 * (a copy is included in the LICENSE file that accompanied this code).
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with OpenOffice.org.  If not, see
 * <http://www.openoffice.org/license.html>
 * for a copy of the LGPLv3 License.
 *
 ************************************************************************/

#include <comphelper/string.hxx>
#include <tools/tenccvt.hxx>
#include <osl/thread.h>

#include <vcl/virdev.hxx>
#include <tools/stream.hxx>
#include "starmath.hrc"
#include "utility.hxx"

namespace binfilter {

/*N*/ SvStream& operator >> (SvStream& rStream, SmFace& rFont)
/*N*/ {
/*N*/   sal_uInt32 nData;
/*N*/
/*N*/   rtl::OString aByteStr = read_lenPrefixed_uInt8s_ToOString<sal_uInt16>(rStream);
/*N*/   rFont.SetName( ImportString( aByteStr ) );
/*N*/   rStream >> nData;
/*N*/   rFont.SetFamily((FontFamily)nData);
/*N*/   rStream >> nData;
/*N*/   rFont.SetCharSet( GetSOLoadTextEncoding( (rtl_TextEncoding) nData ) );
/*N*/   rStream >> nData;
/*N*/   rFont.SetWeight((FontWeight)nData);
/*N*/   rStream >> nData;
/*N*/   rFont.SetItalic((FontItalic)nData);
/*N*/
/*N*/   return rStream;
/*N*/ }

/*?*/ void ReadSM20Font(SvStream& rStream, Font& rFont)
/*?*/ {
/*?*/   BOOL    bData;
/*?*/   sal_uInt32 nData;
/*?*/
/*?*/   rtl::OString aByteStr = read_lenPrefixed_uInt8s_ToOString<sal_uInt16>(rStream);
/*?*/   rFont.SetName( ImportString( aByteStr ) );
/*?*/   rStream >> nData;
/*?*/   rFont.SetFamily((FontFamily)nData);
/*?*/   rStream >> nData;
/*?*/   rFont.SetCharSet( GetSOLoadTextEncoding( (rtl_TextEncoding) nData ) );
/*?*/   rStream >> nData;
/*?*/   rFont.SetWeight((FontWeight)nData);
/*?*/   rStream >> bData;
/*?*/   if (bData)
/*?*/       rFont.SetItalic(ITALIC_NORMAL);
/*?*/   else
/*?*/       rFont.SetItalic(ITALIC_NONE);
/*?*/ }


////////////////////////////////////////////////////////////
//
// SmRectCache
//

/*N*/ SmRectCache::SmRectCache()
/*N*/ {
/*N*/   pVirDev = 0;
/*N*/ }


/*N*/ SmRectCache::~SmRectCache()
/*N*/ {
/*N*/   delete pVirDev;
/*N*/ }


/*N*/ VirtualDevice * SmRectCache::GetVirDev()
/*N*/ {
/*N*/   if (!pVirDev)
/*N*/   {
            pVirDev = new VirtualDevice;
/*N*/       pVirDev->SetMapMode( MapMode(MAP_100TH_MM) );
/*N*/   }
/*N*/   DBG_ASSERT(pVirDev->GetMapMode().GetMapUnit() == MAP_100TH_MM,
/*N*/              "Sm : falscher MapMode");
/*N*/
/*N*/   return pVirDev;
/*N*/ }


////////////////////////////////////////////////////////////

#define TE_UCS2     "UCS2"
#define PRE_TE      "<?"
#define POST_TE     ")>"

#define TEXTENCODINGTAB_LEN     12

static const struct
{
    const char         *pText;
    rtl_TextEncoding    nEnc;
} aTextEncodingTab[ TEXTENCODINGTAB_LEN ] =
{
    { TE_UCS2,        RTL_TEXTENCODING_UCS2 },  // is RTL_TEXTENCODING_UNICODE in 6.0
    { "DONTKNOW",     RTL_TEXTENCODING_DONTKNOW },
    { "ANSI",         RTL_TEXTENCODING_MS_1252 },
    { "MAC",          RTL_TEXTENCODING_APPLE_ROMAN },
    { "PC437",        RTL_TEXTENCODING_IBM_437 },
    { "PC850",        RTL_TEXTENCODING_ASCII_US },
    { "PC860",        RTL_TEXTENCODING_IBM_860 },
    { "PC861",        RTL_TEXTENCODING_IBM_861 },
    { "PC863",        RTL_TEXTENCODING_IBM_863 },
    { "PC865",        RTL_TEXTENCODING_IBM_865 },
    { "SYSTEM",       RTL_TEXTENCODING_DONTKNOW },
    { "SYMBOL",       RTL_TEXTENCODING_SYMBOL }
};

int GetTextEncodingTabIndex( const String &rTxt, xub_StrLen nPos )
{
    int nRes = -1;
    for (int i = 0;  i < TEXTENCODINGTAB_LEN  &&  nRes == -1;  ++i)
    {
        if (nPos == rTxt.SearchAscii( aTextEncodingTab[i].pText , nPos ))
            nRes = i;
    }
    return nRes;
}

/*N*/ const String ImportString( const ByteString& rByteString )
/*N*/ {
/*N*/     String  aString( rByteString, RTL_TEXTENCODING_MS_1252 );
/*N*/
/*N*/     const xub_StrLen nPreLen  = sizeof( PRE_TE ) - 1;
/*N*/     const xub_StrLen nPostLen = sizeof( POST_TE ) - 1;
/*N*/
/*N*/     xub_StrLen nPreStart = 0;
/*N*/     while( STRING_NOTFOUND != ( nPreStart =
/*N*/                                     aString.SearchAscii( PRE_TE, nPreStart )) )
/*N*/     {
              if (aString.EqualsAscii( "<?>", nPreStart, 3 ))
              {
                  nPreStart += 3;   // restart look-up after current found position
                  continue;
              }

/*?*/         //
/*N*/         // convert 'unknown character' to unicode character
/*N*/         //
/*?*/         xub_StrLen nTeStart = nPreStart + nPreLen;
/*?*/         xub_StrLen nTeLen   = 0;
/*?*/         int nIdx = GetTextEncodingTabIndex( aString, nTeStart );
/*?*/         DBG_ASSERT( nIdx >= 0, "text-encoding is missing" );
/*?*/         rtl_TextEncoding nEnc = RTL_TEXTENCODING_DONTKNOW;
/*?*/         if (nIdx >= 0)
/*?*/         {
/*?*/             nEnc = aTextEncodingTab[ nIdx ].nEnc;
/*?*/             nTeLen = strlen( aTextEncodingTab[ nIdx ].pText );
/*?*/         }
/*?*/         if (RTL_TEXTENCODING_DONTKNOW == nEnc)
/*?*/             nEnc = osl_getThreadTextEncoding();
/*?*/         //
/*?*/         xub_StrLen nNumStart = nTeStart + nTeLen + 1, // +1 because of "("
/*?*/                    nReplLen;
/*?*/         xub_StrLen nPostStart = aString.SearchAscii( POST_TE, nNumStart );
/*?*/         String sRepl;
/*?*/         if( STRING_NOTFOUND != nPostStart )
/*?*/         {
/*?*/             INT32 nCharVal = aString.Copy( nNumStart, nPostStart - nNumStart ).ToInt32();
/*?*/             DBG_ASSERT( nCharVal != 0, "String -> Int32 failed ?" );
/*?*/             if (RTL_TEXTENCODING_UNICODE == nEnc)
/*?*/             {
/*?*/                 if (nCharVal)
/*?*/                     sRepl = (sal_Unicode) nCharVal;
/*?*/             }
/*?*/             else
/*?*/             {
/*?*/                 DBG_ASSERT( 0 <= nCharVal  &&  nCharVal <= 256,
/*?*/                         "character value out of range" );
/*?*/                 sRepl = ByteString::ConvertToUnicode( nCharVal, nEnc );
/*?*/             }
/*?*/             DBG_ASSERT( sRepl.Len() || !nCharVal, "conversion failed" );
/*?*/             nReplLen = nPostStart + nPostLen - nPreStart;
/*?*/         }
/*?*/         else
/*?*/         {
/*?*/             OSL_FAIL( "import error: 'unknown character' delimiter missing" );
/*?*/             sRepl.AssignAscii( RTL_CONSTASCII_STRINGPARAM( "<?>" ) );
/*?*/             nReplLen = nPreLen;
/*?*/         }
/*?*/
/*?*/         aString.Replace( nPreStart, nReplLen, sRepl );
/*?*/         nPreStart += sRepl.Len();
/*N*/     }
/*N*/
/*N*/     // in old 2.0 or 3.0 formulas the strings to be imported do have an
/*N*/     // additional '\0' character at the end that gets removed here.
/*N*/     if (aString.Len())
/*N*/         aString = comphelper::string::stripEnd(aString, '\0');
/*N*/
/*N*/     return convertLineEnd(aString, GetSystemLineEnd());
/*N*/ }

////////////////////////////////////////////////////////////


/**************************************************************************/

/*N*/ SmPickList::SmPickList(USHORT nInitSize, USHORT nMaxSize) :
/*N*/   SfxPtrArr((BYTE) nInitSize, 1)
/*N*/ {
/*N*/   nSize = nMaxSize;
/*N*/ }


/*N*/ SmPickList::~SmPickList()
/*N*/ {
/*N*/   Clear();
/*N*/ }


/*N*/ void SmPickList::Clear()
/*N*/ {
/*N*/   USHORT  nPos;
/*N*/
/*N*/   for (nPos = 0; nPos < Count(); nPos++)
/*?*/       DestroyItem(GetPtr(nPos));
/*N*/
/*N*/   RemovePtr(0, Count());
/*N*/ }

/**************************************************************************/
/**************************************************************************/

String SmFontPickList::GetStringItem(void * /*pItem*/)
{
    DBG_BF_ASSERT(0, "STRIP");  // VIRTUAL
    String aString;
    return aString;
}

////////////////////////////////////////

/*N*/ void SmFace::Impl_Init()
/*N*/ {
/*N*/     SetSize( GetSize() );
/*N*/     SetTransparent( TRUE );
/*N*/     SetAlign( ALIGN_BASELINE );
/*N*/     SetColor( COL_AUTO );
/*N*/ }

/*N*/ void SmFace::SetSize(const Size& rSize)
/*N*/ {
/*N*/   Size  aSize (rSize);
/*N*/
/*N*/   // check the requested size against minimum value
/*N*/   static int const    nMinVal = SmPtsTo100th_mm(2);
/*N*/
/*N*/   if (aSize.Height() < nMinVal)
/*N*/       aSize.Height() = nMinVal;
/*N*/
/*N*/   //! we don't force a maximum value here because this may prevent eg the
/*N*/   //! parentheses in "left ( ... right )" from matching up with large
/*N*/   //! bodies (eg stack{...} with many entries).
/*N*/   //! Of course this is holds only if characters are used and not polygons.
/*N*/
/*N*/   Font::SetSize(aSize);
/*N*/ }


/*N*/ long SmFace::GetBorderWidth() const
/*N*/ {
/*N*/   if (nBorderWidth < 0)
/*N*/       return GetDefaultBorderWidth();
/*N*/   else
/*N*/       return nBorderWidth;
/*N*/ }

/*N*/ SmFace & SmFace::operator = (const SmFace &rFace)
/*N*/ {
/*N*/   Font::operator = (rFace);
/*N*/   nBorderWidth = -1;
/*N*/   return *this;
/*N*/ }


/*N*/ SmFace & operator *= (SmFace &rFace, const Fraction &rFrac)
/*N*/   // scales the width and height of 'rFace' by 'rFrac' and returns a
/*N*/   // reference to 'rFace'.
/*N*/   // It's main use is to make scaling fonts look easier.
/*N*/ { const Size &rFaceSize = rFace.GetSize();
/*N*/
/*N*/   rFace.SetSize(Size(Fraction(rFaceSize.Width())  *= rFrac,
/*N*/                      Fraction(rFaceSize.Height()) *= rFrac));
/*N*/   return rFace;
/*N*/ }

}

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
