/*
 * BEGIN FLOCK GPL
 *
 * Copyright Flock Inc. 2005-2009
 * http://flock.com
 *
 * This file may be used under the terms of the
 * GNU General Public License Version 2 or later (the "GPL"),
 * http://www.gnu.org/licenses/gpl.html
 *
 * 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.
 *
 * END FLOCK GPL
 */

/* This is largely based off of nsAboutRedirector.cpp */

#include "flockAboutRedirector.h"
#include "flockIDocShellBridge.h"
#include "nsNetUtil.h"
#include "nsIScriptSecurityManager.h"


NS_IMPL_ISUPPORTS1(flockAboutRedirector, nsIAboutModule)


struct RedirEntry {
  const char *id;
  const char *url;
  PRUint32 flags;
};

static RedirEntry kRedirMap[] = {
  { "duck", "http://www.flock.com/duck/",
    nsIAboutModule::URI_SAFE_FOR_UNTRUSTED_CONTENT },
  { "myworld", "chrome://flock/content/start/myworld.xul", 0 },
  { "webdetective", "chrome://flock/content/common/aboutWD.xhtml", 0 },
  { "flock", "chrome://flock/content/oobe/gettingStarted.xhtml", 0 },
  { "flockbuild", "chrome://flock/content/common/aboutBuild.xhtml", 0 },
  { "flockdnsnotfound", "chrome://global/content/netError.xhtml",
    nsIAboutModule::URI_SAFE_FOR_UNTRUSTED_CONTENT },
  { "tutorial", "chrome://flock/content/oobe/tutorial.xhtml", 0 }
};

static const int kRedirTotal = NS_ARRAY_LENGTH(kRedirMap);


static inline nsresult
GetAboutModuleName(nsIURI *aAboutURI, nsCString& aModule)
{
  nsresult rv = aAboutURI->GetPath(aModule);
  NS_ENSURE_SUCCESS(rv, rv);

  PRInt32 pos;

  pos = aModule.Find("#");
  if (pos == -1) {
    pos = aModule.Find("?");
  }

  if (pos != -1) {
    aModule.SetLength(pos);
  }

  // convert to lowercase, as all about: modules are lowercase
  ToLowerCase(aModule);
  return NS_OK;
}

NS_IMETHODIMP
flockAboutRedirector::NewChannel(nsIURI *aURI, nsIChannel **result)
{
  NS_ENSURE_ARG_POINTER(aURI);
  NS_ASSERTION(result, "must not be null");

  nsresult rv;

  nsCAutoString path;
  rv = GetAboutModuleName(aURI, path);
  NS_ENSURE_SUCCESS(rv, rv);

  nsCOMPtr<nsIIOService> ioService = do_GetIOService(&rv);
  NS_ENSURE_SUCCESS(rv, rv);

  for (int i = 0; i < kRedirTotal; i++) {
    if (path.Equals(kRedirMap[i].id)) {
      nsCAutoString redirURL;
      nsCOMPtr<nsIChannel> tempChannel;

      if (path.EqualsLiteral("flockdnsnotfound")) {
        // On a DNS error we redirect to a search page.
        nsCOMPtr<flockIDocShellBridge> docshellBridge =
          do_GetService("@flock.com/docshell-bridge;1", &rv);
        NS_ENSURE_SUCCESS(rv, rv);

        rv = docshellBridge->GetDNSNotFoundURL(aURI, redirURL);
        NS_ENSURE_SUCCESS(rv, rv);
      }

      if (!redirURL.IsEmpty()) {
        rv = ioService->NewChannel(redirURL,
                                   nsnull,
                                   nsnull,
                                   getter_AddRefs(tempChannel));
      } else {
        rv = ioService->NewChannel(nsDependentCString(kRedirMap[i].url),
                                   nsnull,
                                   nsnull,
                                   getter_AddRefs(tempChannel));
      }

      NS_ENSURE_SUCCESS(rv, rv);

      tempChannel->SetOriginalURI(aURI);

      // Keep the page from getting unnecessary privileges unless it needs them
      if (kRedirMap[i].flags &
          nsIAboutModule::URI_SAFE_FOR_UNTRUSTED_CONTENT)
      {
        nsCOMPtr<nsIScriptSecurityManager> securityManager =
          do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID, &rv);
        NS_ENSURE_SUCCESS(rv, rv);

        nsCOMPtr<nsIPrincipal> principal;
        rv = securityManager->GetCodebasePrincipal(aURI,
                                                   getter_AddRefs(principal));
        NS_ENSURE_SUCCESS(rv, rv);

        rv = tempChannel->SetOwner(principal);
        NS_ENSURE_SUCCESS(rv, rv);
      }

      NS_ADDREF(*result = tempChannel);
      return rv;
    }
  }

  NS_ERROR("flockAboutRedirector called for unknown case");
  return NS_ERROR_ILLEGAL_VALUE;
}

NS_IMETHODIMP
flockAboutRedirector::GetURIFlags(nsIURI *aURI, PRUint32 *result)
{
  NS_ENSURE_ARG_POINTER(aURI);

  nsCAutoString name;
  nsresult rv = GetAboutModuleName(aURI, name);
  NS_ENSURE_SUCCESS(rv, rv);

  for (int i = 0; i < kRedirTotal; i++) {
    if (name.Equals(kRedirMap[i].id)) {
      *result = kRedirMap[i].flags;
      return NS_OK;
    }
  }

  NS_ERROR("flockAboutRedirector called for unknown case");
  return NS_ERROR_ILLEGAL_VALUE;
}

NS_METHOD
flockAboutRedirector::Create(nsISupports *aOuter, REFNSIID aIID, void **aResult)
{
  flockAboutRedirector* about = new flockAboutRedirector();
  if (about == nsnull)
    return NS_ERROR_OUT_OF_MEMORY;
  NS_ADDREF(about);
  nsresult rv = about->QueryInterface(aIID, aResult);
  NS_RELEASE(about);
  return rv;
}
