/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* ***** BEGIN LICENSE BLOCK *****
 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
 *
 * The contents of this file are subject to the Mozilla Public License Version
 * 1.1 (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.mozilla.org/MPL/
 *
 * Software distributed under the License is distributed on an "AS IS" basis,
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
 * for the specific language governing rights and limitations under the
 * License.
 *
 * The Original Code is mozilla.org code.
 *
 * The Initial Developer of the Original Code is
 * Netscape Communications Corporation.
 * Portions created by the Initial Developer are Copyright (C) 2002
 * the Initial Developer. All Rights Reserved.
 *
 * Contributor(s):
 *  Conrad Carlen <ccarlen@netscape.com>
 *
 * Alternatively, the contents of this file may be used under the terms of
 * either the GNU General Public License Version 2 or later (the "GPL"), or
 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
 * in which case the provisions of the GPL or the LGPL are applicable instead
 * of those above. If you wish to allow use of your version of this file only
 * under the terms of either the GPL or the LGPL, and not to allow others to
 * use your version of this file under the terms of the MPL, indicate your
 * decision by deleting the provisions above and replace them with the notice
 * and other provisions required by the GPL or the LGPL. If you do not delete
 * the provisions above, a recipient may use your version of this file under
 * the terms of any one of the MPL, the GPL or the LGPL.
 *
 * ***** END LICENSE BLOCK ***** */

#include "CWindowCreator.h"

#include "nsIWindowWatcher.h"
#include "nsIServiceManagerUtils.h"

#include "CBrowserShell.h"
#include "CBrowserWindow.h"
#include "ApplIDs.h"

// ---------------------------------------------------------------------------
//  CWindowCreator
// ---------------------------------------------------------------------------

NS_IMPL_ISUPPORTS1(CWindowCreator, nsIWindowCreator);

CWindowCreator::CWindowCreator()
{
    NS_INIT_ISUPPORTS();
}

CWindowCreator::~CWindowCreator()
{
}

NS_IMETHODIMP CWindowCreator::CreateChromeWindow(nsIWebBrowserChrome *aParent,
                                                 PRUint32 aChromeFlags,
                                                 nsIWebBrowserChrome **_retval)
{
    NS_ENSURE_ARG_POINTER(_retval);
    *_retval = 0;

    // we're ignoring aParent,
    // but since windows on the Mac don't have parents anyway...
    try {
        LWindow *theWindow = CreateWindowInternal(aChromeFlags, -1, -1);
        CBrowserShell *browser = dynamic_cast<CBrowserShell*>(theWindow->FindPaneByID(CBrowserShell::paneID_MainBrowser));
        ThrowIfNil_(browser);
        browser->GetWebBrowserChrome(_retval);
    } catch(...) {
        return NS_ERROR_FAILURE;
    }

    return NS_OK;
}


/*
   InitializeWindowCreator creates and hands off an object with a callback
   to a window creation function. This will be used by Gecko C++ code
   (never JS) to create new windows when no previous window is handy
   to begin with. This is done in a few exceptional cases, like PSM code.
   Failure to set this callback will only disable the ability to create
   new windows under these circumstances.
*/

nsresult CWindowCreator::Initialize()
{
    // Create a CWindowCreator and give it to the WindowWatcher service
    // The WindowWatcher service will own it so we don't keep a ref.
    CWindowCreator *windowCreator = new CWindowCreator;
    if (!windowCreator) return NS_ERROR_FAILURE;
    
    nsCOMPtr<nsIWindowWatcher> wwatch(do_GetService("@mozilla.org/embedcomp/window-watcher;1"));
    if (!wwatch) return NS_ERROR_FAILURE;
    return wwatch->SetWindowCreator(windowCreator);
}

LWindow* CWindowCreator::CreateWindowInternal(PRUint32 inChromeFlags,
                                              PRInt32 width, PRInt32 height)
{
    const SInt16 kStatusBarHeight = 16;
    
    LWindow         *theWindow;
    PRUint32        chromeFlags;
    
    if (inChromeFlags == nsIWebBrowserChrome::CHROME_DEFAULT)
        chromeFlags = nsIWebBrowserChrome::CHROME_WINDOW_RESIZE |
                      nsIWebBrowserChrome::CHROME_WINDOW_CLOSE |
                      nsIWebBrowserChrome::CHROME_TOOLBAR |
                      nsIWebBrowserChrome::CHROME_STATUSBAR;
    else
        chromeFlags = inChromeFlags;
    
    // Bounds - Set to an arbitrary rect - we'll size it after all the subviews are in.
    Rect globalBounds;
    globalBounds.left = 4;
    globalBounds.top = 42;
    globalBounds.right = globalBounds.left + 600;
    globalBounds.bottom = globalBounds.top + 400;
    
    // ProcID and attributes
    short windowDefProc;
    UInt32 windowAttrs = (windAttr_Enabled | windAttr_Targetable);
    if (chromeFlags & nsIWebBrowserChrome::CHROME_OPENAS_DIALOG)
    {
        windowAttrs |= windAttr_Modal;

        if (chromeFlags & nsIWebBrowserChrome::CHROME_TITLEBAR)
        {
            windowDefProc = kWindowMovableModalDialogProc;
            windowAttrs |= windAttr_TitleBar;
        }
        else
            windowDefProc = kWindowModalDialogProc;            
    }
    else
    {
        windowAttrs |= windAttr_Regular;    

        if (chromeFlags & nsIWebBrowserChrome::CHROME_WINDOW_RESIZE)
        {
            windowDefProc = kWindowGrowDocumentProc;
            windowAttrs |= windAttr_Resizable;
        }
        else
            windowDefProc = kWindowDocumentProc;            
        
        if (chromeFlags & nsIWebBrowserChrome::CHROME_WINDOW_CLOSE)
            windowAttrs |= windAttr_CloseBox;
    }
    
    theWindow = new CBrowserWindow(LCommander::GetTopCommander(), globalBounds, "\p", windowDefProc, windowAttrs, window_InFront);
    ThrowIfNil_(theWindow);

    SDimension16 windowSize, toolBarSize;
    theWindow->GetFrameSize(windowSize);

    if (chromeFlags & nsIWebBrowserChrome::CHROME_TOOLBAR)
    {
        LView::SetDefaultView(theWindow);
        LCommander::SetDefaultCommander(theWindow);
        LAttachable::SetDefaultAttachable(nil);

        LView *toolBarView = static_cast<LView*>(UReanimator::ReadObjects(ResType_PPob, 131));
        ThrowIfNil_(toolBarView);
                    
        toolBarView->GetFrameSize(toolBarSize);
        toolBarView->PlaceInSuperFrameAt(0, 0, false);
        toolBarSize.width = windowSize.width;
        toolBarView->ResizeFrameTo(toolBarSize.width, toolBarSize.height, false);
    }

    SPaneInfo aPaneInfo;
    SViewInfo aViewInfo;
    
    aPaneInfo.paneID = CBrowserShell::paneID_MainBrowser;
    aPaneInfo.width = windowSize.width;
    aPaneInfo.height = windowSize.height;
    if (chromeFlags & nsIWebBrowserChrome::CHROME_TOOLBAR)
        aPaneInfo.height -= toolBarSize.height;
    if (chromeFlags & nsIWebBrowserChrome::CHROME_STATUSBAR)
        aPaneInfo.height -= kStatusBarHeight - 1;
    aPaneInfo.visible = true;
    aPaneInfo.enabled = true;
    aPaneInfo.bindings.left = true;
    aPaneInfo.bindings.top = true;
    aPaneInfo.bindings.right = true;
    aPaneInfo.bindings.bottom = true;
    aPaneInfo.left = 0;
    aPaneInfo.top = (chromeFlags & nsIWebBrowserChrome::CHROME_TOOLBAR) ? toolBarSize.height : 0;
    aPaneInfo.userCon = 0;
    aPaneInfo.superView = theWindow;
    
    aViewInfo.imageSize.width = 0;
    aViewInfo.imageSize.height = 0;
    aViewInfo.scrollPos.h = aViewInfo.scrollPos.v = 0;
    aViewInfo.scrollUnit.h = aViewInfo.scrollUnit.v = 1;
    aViewInfo.reconcileOverhang = 0;
    
    CBrowserShell *aShell = new CBrowserShell(aPaneInfo, aViewInfo, chromeFlags, PR_TRUE);
    ThrowIfNil_(aShell);
    aShell->AddAttachments();
    aShell->PutInside(theWindow, false);
   
    if (chromeFlags & nsIWebBrowserChrome::CHROME_STATUSBAR)
    {
        LView::SetDefaultView(theWindow);
        LCommander::SetDefaultCommander(theWindow);
        LAttachable::SetDefaultAttachable(nil);

        LView *statusView = static_cast<LView*>(UReanimator::ReadObjects(ResType_PPob, 130));
        ThrowIfNil_(statusView);
        
        statusView->PlaceInSuperFrameAt(0, windowSize.height - kStatusBarHeight + 1, false);
        statusView->ResizeFrameTo(windowSize.width - 15, kStatusBarHeight, false);
    }        
    
    // Now the window is constructed...
    theWindow->FinishCreate();        

    Rect    theBounds;
    theWindow->GetGlobalBounds(theBounds);
    if (width == -1)
        width = theBounds.right - theBounds.left;
    if (height == -1)
        height = theBounds.bottom - theBounds.top;
        
    theWindow->ResizeWindowTo(width, height);

    return theWindow;
}
