/**************************************************************
 * 
 * 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_desktop.hxx"

#include "dp_misc.hrc"
#include "dp_misc.h"
#include "dp_ucb.h"
#include "rtl/uri.hxx"
#include "rtl/ustrbuf.hxx"
#include "ucbhelper/content.hxx"
#include "xmlscript/xml_helper.hxx"
#include "com/sun/star/io/XInputStream.hpp"
#include "com/sun/star/ucb/CommandFailedException.hpp"
#include "com/sun/star/ucb/ContentInfo.hpp"
#include "com/sun/star/ucb/ContentInfoAttribute.hpp"


using namespace ::com::sun::star;
using namespace ::com::sun::star::uno;
using namespace ::com::sun::star::ucb;
using ::rtl::OUString;

namespace dp_misc
{

const OUString StrTitle::operator () ()
{
    return OUSTR("Title");
}

//==============================================================================
bool create_ucb_content(
    ::ucbhelper::Content * ret_ucbContent, OUString const & url,
    Reference<XCommandEnvironment> const & xCmdEnv,
    bool throw_exc )
{
    try {
        // Existense check...
        // content ctor/isFolder() will throw exception in case the resource
        // does not exist.

        // dilemma: no chance to use the given iahandler here, because it would
        //          raise no such file dialogs, else no interaction for
        //          passwords, ...? xxx todo
        ::ucbhelper::Content ucbContent(
            url, Reference<XCommandEnvironment>() );

        ucbContent.isFolder();

        if (ret_ucbContent != 0)
        {
            ucbContent.setCommandEnvironment( xCmdEnv );
            *ret_ucbContent = ucbContent;
        }
        return true;
    }
    catch (RuntimeException &) {
        throw;
    }
    catch (Exception &) {
        if (throw_exc)
            throw;
    }
    return false;
}

//==============================================================================
bool create_folder(
    ::ucbhelper::Content * ret_ucb_content, OUString const & url_,
    Reference<XCommandEnvironment> const & xCmdEnv, bool throw_exc )
{
    ::ucbhelper::Content ucb_content;
    if (create_ucb_content(
            &ucb_content, url_, xCmdEnv, false /* no throw */ ))
    {
        if (ucb_content.isFolder()) {
            if (ret_ucb_content != 0)
                *ret_ucb_content = ucb_content;
            return true;
        }
    }

    OUString url( url_ );
    // xxx todo: find parent
    sal_Int32 slash = url.lastIndexOf( '/' );
    if (slash < 0) {
        // fallback:
        url = expandUnoRcUrl( url );
        slash = url.lastIndexOf( '/' );
    }
    if (slash < 0) {
        // invalid: has to be at least "auth:/..."
        if (throw_exc)
            throw ContentCreationException(
                OUSTR("Cannot create folder (invalid path): ") + url,
                Reference<XInterface>(), ContentCreationError_UNKNOWN );
        return false;
    }
    ::ucbhelper::Content parentContent;
    if (! create_folder(
            &parentContent, url.copy( 0, slash ), xCmdEnv, throw_exc ))
        return false;
    const Any title( ::rtl::Uri::decode( url.copy( slash + 1 ),
                                         rtl_UriDecodeWithCharset,
                                         RTL_TEXTENCODING_UTF8 ) );
    const Sequence<ContentInfo> infos(
        parentContent.queryCreatableContentsInfo() );
    for ( sal_Int32 pos = 0; pos < infos.getLength(); ++pos )
    {
        // look KIND_FOLDER:
        ContentInfo const & info = infos[ pos ];
        if ((info.Attributes & ContentInfoAttribute::KIND_FOLDER) != 0)
        {
            // make sure the only required bootstrap property is "Title":
            Sequence<beans::Property> const & rProps = info.Properties;
            if (rProps.getLength() != 1 ||
                !rProps[ 0 ].Name.equalsAsciiL(
                    RTL_CONSTASCII_STRINGPARAM("Title") ))
                continue;

            try {
                if (parentContent.insertNewContent(
                        info.Type,
                        Sequence<OUString>( &StrTitle::get(), 1 ),
                        Sequence<Any>( &title, 1 ),
                        ucb_content )) {
                    if (ret_ucb_content != 0)
                        *ret_ucb_content = ucb_content;
                    return true;
                }
            }
            catch (RuntimeException &) {
                throw;
            }
            catch (CommandFailedException &) {
                // Interaction Handler already handled the error
                // that has occurred...
            }
            catch (Exception &) {
                if (throw_exc)
                    throw;
                return false;
            }
        }
    }
    if (throw_exc)
        throw ContentCreationException(
            OUSTR("Cannot create folder: ") + url,
            Reference<XInterface>(), ContentCreationError_UNKNOWN );
    return false;
}

//==============================================================================
bool erase_path( OUString const & url,
                 Reference<XCommandEnvironment> const & xCmdEnv,
                 bool throw_exc )
{
    ::ucbhelper::Content ucb_content;
    if (create_ucb_content( &ucb_content, url, xCmdEnv, false /* no throw */ ))
    {
        try {
            ucb_content.executeCommand(
                OUSTR("delete"), Any( true /* delete physically */ ) );
        }
        catch (RuntimeException &) {
            throw;
        }
        catch (Exception &) {
            if (throw_exc)
                throw;
            return false;
        }
    }
    return true;
}

//==============================================================================
::rtl::ByteSequence readFile( ::ucbhelper::Content & ucb_content )
{
    ::rtl::ByteSequence bytes;
    Reference<io::XOutputStream> xStream(
        ::xmlscript::createOutputStream( &bytes ) );
    if (! ucb_content.openStream( xStream ))
        throw RuntimeException(
            OUSTR(
                "::ucbhelper::Content::openStream( XOutputStream ) failed!"),
            0 );
    return bytes;
}

//==============================================================================
bool readLine( OUString * res, OUString const & startingWith,
               ::ucbhelper::Content & ucb_content, rtl_TextEncoding textenc )
{
    // read whole file:
    ::rtl::ByteSequence bytes( readFile( ucb_content ) );
    OUString file( reinterpret_cast<sal_Char const *>(bytes.getConstArray()),
                   bytes.getLength(), textenc );
    sal_Int32 pos = 0;
    for (;;)
    {
        if (file.match( startingWith, pos ))
        {
            ::rtl::OUStringBuffer buf;
            sal_Int32 start = pos;
            pos += startingWith.getLength();
            for (;;)
            {
                pos = file.indexOf( LF, pos );
                if (pos < 0) { // EOF
                    buf.append( file.copy( start ) );
                }
                else
                {
                    if (pos > 0 && file[ pos - 1 ] == CR)
                    {
                        // consume extra CR
                        buf.append( file.copy( start, pos - start - 1 ) );
                        ++pos;
                    }
                    else
                        buf.append( file.copy( start, pos - start ) );
                    ++pos; // consume LF
                    // check next line:
                    if (pos < file.getLength() &&
                        (file[ pos ] == ' ' || file[ pos ] == '\t'))
                    {
                        buf.append( static_cast<sal_Unicode>(' ') );
                        ++pos;
                        start = pos;
                        continue;
                    }
                }
                break;
            }
            *res = buf.makeStringAndClear();
            return true;
        }
        // next line:
        sal_Int32 next_lf = file.indexOf( LF, pos );
        if (next_lf < 0) // EOF
            break;
        pos = next_lf + 1;
    }
    return false;
}

bool readProperties( ::std::list< ::std::pair< ::rtl::OUString, ::rtl::OUString> > & out_result,
                     ::ucbhelper::Content & ucb_content )
{
    // read whole file:
    ::rtl::ByteSequence bytes( readFile( ucb_content ) );
    OUString file( reinterpret_cast<sal_Char const *>(bytes.getConstArray()),
                   bytes.getLength(), RTL_TEXTENCODING_UTF8);
    sal_Int32 pos = 0;
    
    for (;;)
    {

        ::rtl::OUStringBuffer buf;
        sal_Int32 start = pos;

        bool bEOF = false;
        pos = file.indexOf( LF, pos );
        if (pos < 0) { // EOF
            buf.append( file.copy( start ) );
            bEOF = true;
        }
        else
        {
            if (pos > 0 && file[ pos - 1 ] == CR)
                // consume extra CR
                buf.append( file.copy( start, pos - start - 1 ) );
            else
                buf.append( file.copy( start, pos - start ) );
            pos++;
        }
        OUString aLine = buf.makeStringAndClear();
        
        sal_Int32 posEqual = aLine.indexOf('=');
        if (posEqual > 0 && (posEqual + 1) <  aLine.getLength())
        {
            OUString name = aLine.copy(0, posEqual);
            OUString value = aLine.copy(posEqual + 1);
            out_result.push_back(::std::make_pair(name, value));
        }

        if (bEOF)
            break;
    }
    return false;
}

}
