/*
* Copyright (c) 2007 Nokia Corporation and/or its subsidiary(-ies).
* All rights reserved.
* This component and the accompanying materials are made available
* under the terms of the License "Eclipse Public License v1.0"
* which accompanies this distribution, and is available
* at the URL "http://www.eclipse.org/legal/epl-v10.html".
*
* Initial Contributors:
* Nokia Corporation - initial contribution.
*
* Contributors:
*
* Description:  
*
*/

#include "config.h"
#include <../bidi.h>
#include <Uri8.h>
#include <badesca.h>

#include "ResourceLoaderDelegate.h"
#include "UrlConnection.h"
#include "DataConnection.h"
#include "FileConnection.h"
#include "HttpConnection.h"
#include "ResolvedConnection.h"

#include "ResourceHandleInternal.h"
#include "DocumentLoader.h"
#include "ResourceHandle.h"
#include "KUrl.h"
#include "FrameLoader.h"
#include "DocumentLoader.h"
#include "Frame.h"

#include "brctl.h"
#include "page.h"
#include "WebUtil.h"
#include "WebFrame.h"
#include "SettingsContainer.h"
#include "BrCtlSpecialLoadObserver.h"
#include "BrCtlLinkResolver.h"
#include "WebDocumentLoader.h"
#include "WebView.h"

_LIT8(KHttp, "http");
_LIT8(KHttps, "https");

using namespace WebCore;

MUrlConnection* ResourceLoaderDelegate::CreateUrlConnection(ResourceHandle* handle, Frame* frame)
{
    MUrlConnection* connection = NULL;
    TInt err = KErrNone;
    ResourceRequest r = handle->request();
    TRAP(err, connection = checkLinkResolverL(handle, frame));
    if (err == KErrNone && !connection) {
        if (checkSecurityStatus(handle->request(), frame)) {
            TPtrC8 url(r.url().des());
            TUriParser8 parser;
            TInt status = parser.Parse( url );
            TInt ret = EFalse;
            if( status == KErrNone ) {
                TPtrC8 scheme = parser.Extract( EUriScheme );
                if (scheme.CompareF( KHttp ) == 0 || scheme.CompareF( KHttps ) == 0) {
                    connection = new HttpConnection(handle, frame);
                }
                else if (scheme.Length() == 1 || scheme.CompareF( _L8("file") ) == 0) {
                    connection = new FileConnection(handle);
                }
                else if (scheme.CompareF( _L8("data") ) == 0) {
                    connection = new DataConnection(handle);
                }
                else {
                    TRAP(err, handleSpecialSchemeL(r.url().des(), frame));
                    if (err == KErrNotFound) {
                        err = KErrHttpInvalidUri;
                    }
                }
            }
        }
    }
    if (r.mainLoad() && frame == frame->page()->mainFrame() && err != KErrNone && err != KErrCancel) {
		m_httpSessionManager.uiCallback()->reportError(mapHttpErrors(err));
    }
    return connection;
}

void ResourceLoaderDelegate::download(ResourceHandle* handle, const ResourceRequest& request,
                                      const WebCore::ResourceResponse& response)
{
    MUrlConnection* connection = handle->getInternal()->m_connection;
    connection->download(handle, request, response);
}

MUrlConnection* ResourceLoaderDelegate::checkLinkResolverL(ResourceHandle* handle, Frame* frame)
{
    CBrCtl* brctl = control(frame);
    ResolvedConnection* connection = NULL;
    int cnt = 0;
    if (brctl->brCtlLinkResolver()) {
        if (handle->request().mainLoad() && (brctl->capabilities() & TBrCtlDefs::ECapabilityClientNotifyURL)) {
            HBufC* url = HBufC::NewLC(handle->request().url().des().Length());
            cnt++;
            url->Des().Copy(handle->request().url().des());
            HBufC* currentUrl = NULL;
            TPtrC currentUrlPtr(KNullDesC);
            if (frame->loader() && frame->loader()->documentLoader()) {
                TPtrC8 currentUrl8 = frame->loader()->documentLoader()->URL().des();
                currentUrl = HBufC::NewLC(currentUrl8.Length());
                cnt++;
                if (currentUrl) {
                    currentUrl->Des().Copy(currentUrl8);
                    currentUrlPtr.Set(currentUrl->Des());
                }
            }            
            connection = new (ELeave) ResolvedConnection(handle, frame);
            CleanupStack::PushL(connection);
            TBool ret = brctl->brCtlLinkResolver()->ResolveLinkL(url->Des(), currentUrlPtr, *connection);
            CleanupStack::Pop(); // connection
            if (!ret) {
                delete connection;
                connection = NULL;
            }
        }
        else if (!handle->request().mainLoad() && (brctl->capabilities() & TBrCtlDefs::ECapabilityClientResolveEmbeddedURL)) {
            HBufC* url = HBufC::NewLC(handle->request().url().des().Length());
            cnt++;
            url->Des().Copy(handle->request().url().des());
            HBufC* currentUrl = NULL;
            TPtrC currentUrlPtr(KNullDesC);
            if (frame->loader() && frame->loader()->documentLoader()) {
                TPtrC8 currentUrl8 = frame->loader()->documentLoader()->URL().des();
                currentUrl = HBufC::NewLC(currentUrl8.Length());
                cnt++;
                if (currentUrl) {
                    currentUrl->Des().Copy(currentUrl8);
                    currentUrlPtr.Set(currentUrl->Des());
                }
            }            
            connection = new (ELeave) ResolvedConnection(handle, frame);
            CleanupStack::PushL(connection);
            TBool ret = brctl->brCtlLinkResolver()->ResolveEmbeddedLinkL(url->Des(), currentUrlPtr,
                ELoadContentTypeAny, *connection);
            CleanupStack::Pop(); // connection
            if (!ret) {
                delete connection;
                connection = NULL;
            }
        }
        CleanupStack::PopAndDestroy(cnt); // url, currentUrl
    }
    return connection;
}

bool ResourceLoaderDelegate::checkSecurityStatus(const ResourceRequest& request, Frame* frame)
{
    CBrCtl* brctl = control(frame);
    WebDocumentLoader* topDocumentLoader = static_cast<WebDocumentLoader*>(core(brctl->webView()->mainFrame())->loader()->documentLoader());
    HttpUiCallbacks::TEnterStatus enterStatus = HttpUiCallbacks::EEnterStatusNone;
    bool ret = true;
    
    if (brctl->settings()->brctlSetting(TBrCtlDefs::ESettingsSecurityWarnings)) {
        TUriParser8 parser;
        bool secureUrl = false;
        bool currentSecureUrl = false;
        if (parser.Parse(request.url().des()) == KErrNone) {
            TPtrC8 scheme = parser.Extract( EUriScheme );
            secureUrl = scheme.CompareF(KHttps) == 0;
        }
        if (frame->loader() && frame->loader()->documentLoader()) {
            TPtrC8 url = frame->loader()->documentLoader()->URL().des();
            TUriParser8 parser;
            if (parser.Parse(url) == KErrNone) {
                TPtrC8 scheme = parser.Extract( EUriScheme );
                currentSecureUrl = scheme.CompareF(KHttps) == 0;
            }
        }
        if (request.mainLoad()) {
            if (!frame->ownerElement()) {
                if (currentSecureUrl) {
                    if (!secureUrl) {
                        // secure -> non secure
                        if (request.httpMethod() == "POST") {
                            enterStatus = HttpUiCallbacks::ESubmittingToNonSecurePage;
                        }
                        else {
                            enterStatus = HttpUiCallbacks::EExitingSecurePage;
                        }
                    } // if (!secureUrl)
                }
                else {
                    if (secureUrl) {
                        // non secure -> secure
                        enterStatus = HttpUiCallbacks::EEnteringSecurePage;
                    }
                } // if (currentSecureUrl)
            } // if (!frame->ownerElement())
        }
        else
        {
            if (currentSecureUrl) {
                if (!secureUrl) {
                    // Ask once per page. If we already asked, just use the previous user decision
                    if (topDocumentLoader->userWasAskedToLoadNonSecureItem()) {
                        ret = topDocumentLoader->userAgreedToLoadNonSecureItem();
                    }
                    else {
                        enterStatus = HttpUiCallbacks::ESomeItemsNotSecure;
                    }
                }
            }
            else {
                if (secureUrl) {
                    enterStatus = HttpUiCallbacks::ESecureItemInNonSecurePage;
                }
            }
        }
    }
    if (enterStatus != HttpUiCallbacks::EEnterStatusNone) {
        int err = m_httpSessionManager.uiCallback()->aboutToLoadPage(brctl, enterStatus);
        if (err != KErrNone) {
            ret = false;
        }
        if (enterStatus == HttpUiCallbacks::ESomeItemsNotSecure) {
            // Remember user decision
            topDocumentLoader->setUserAgreedToLoadNonSecureItem(ret);
        }
    }
    return ret;
}

bool ResourceLoaderDelegate::handleSpecialSchemeL(TPtrC8 url8, Frame* frame)
{
    // only the url is supported currently
    RArray<TUint> typeArray;
    CDesCArrayFlat* strArray = new( ELeave )CDesCArrayFlat( 1 );
    CleanupStack::PushL( strArray );
    // add url id
    typeArray.Append( EParamRequestUrl );
    HBufC* url = NULL;
    url = HBufC::NewLC(url8.Length());
    TPtr urlPtr(url->Des());
    urlPtr.Copy(url8);
    // add url string
    strArray->AppendL( urlPtr );
    TBool handle( EFalse );
    CBrCtl* brctl = control(frame);
    if (brctl->brCtlSpecialLoadObserver()) {
        brctl->brCtlSpecialLoadObserver()->HandleRequestL( &typeArray, strArray );
    }
    CleanupStack::PopAndDestroy(2); // strArray, url
    return handle;
}

// end of file
