// Copyright 2017 The Cobalt Authors. All Rights Reserved.
//
// Licensed 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.

#include "cobalt/browser/splash_screen_cache.h"

#include <memory>
#include <string>

#include "base/optional.h"
#include "base/strings/string_util.h"
#include "base/synchronization/lock.h"
#include "cobalt/base/get_application_key.h"
#include "starboard/directory.h"
#include "starboard/file.h"
#include "starboard/string.h"

namespace cobalt {
namespace browser {
namespace {
bool CreateDirsForKey(const std::string& key) {
  char path[SB_FILE_MAX_PATH] = {0};
  if (!SbSystemGetPath(kSbSystemPathCacheDirectory, path, SB_FILE_MAX_PATH)) {
    return false;
  }
  std::size_t prev_found = 0;
  std::size_t found = key.find(SB_FILE_SEP_STRING);
  SbStringConcat(path, SB_FILE_SEP_STRING, SB_FILE_MAX_PATH);
  while (found != std::string::npos) {
    SbStringConcat(path, key.substr(prev_found, found - prev_found).c_str(),
                   SB_FILE_MAX_PATH);
    if (!SbDirectoryCreate(path)) {
      return false;
    }
    prev_found = found;
    found = key.find(SB_FILE_SEP_STRING, prev_found + 1);
  }
  return true;
}

}  // namespace

SplashScreenCache::SplashScreenCache() { base::AutoLock lock(lock_); }

bool SplashScreenCache::CacheSplashScreen(const std::string& key,
                                          const std::string& content) const {
  base::AutoLock lock(lock_);
  if (key.empty()) {
    return false;
  }

  char path[SB_FILE_MAX_PATH] = {0};
  if (!SbSystemGetPath(kSbSystemPathCacheDirectory, path, SB_FILE_MAX_PATH)) {
    return false;
  }
  if (!CreateDirsForKey(key)) {
    return false;
  }
  std::string full_path = path + (SB_FILE_SEP_STRING + key);
  starboard::ScopedFile cache_file(
      full_path.c_str(), kSbFileCreateAlways | kSbFileWrite, NULL, NULL);

  return cache_file.WriteAll(content.c_str(),
                             static_cast<int>(content.size())) > 0;
}

bool SplashScreenCache::IsSplashScreenCached(const std::string& key) const {
  base::AutoLock lock(lock_);
  char path[SB_FILE_MAX_PATH] = {0};
  if (!SbSystemGetPath(kSbSystemPathCacheDirectory, path, SB_FILE_MAX_PATH)) {
    return false;
  }
  std::string full_path = path + (SB_FILE_SEP_STRING + key);
  return !key.empty() && SbFileExists(full_path.c_str());
}

int SplashScreenCache::ReadCachedSplashScreen(
    const std::string& key, std::unique_ptr<char[]>* result) const {
  base::AutoLock lock(lock_);
  if (!result) {
    return 0;
  }
  char path[SB_FILE_MAX_PATH] = {0};
  if (!SbSystemGetPath(kSbSystemPathCacheDirectory, path, SB_FILE_MAX_PATH)) {
    result->reset();
    return 0;
  }
  std::string full_path = path + (SB_FILE_SEP_STRING + key);
  starboard::ScopedFile cache_file(full_path.c_str(),
                                   kSbFileOpenOnly | kSbFileRead, NULL, NULL);
  SbFileInfo info;
  bool success = SbFileGetPathInfo(full_path.c_str(), &info);
  if (!success) {
    result->reset();
    return 0;
  }
  const int kFileSize = static_cast<int>(info.size);
  result->reset(new char[kFileSize]);
  int result_size = cache_file.ReadAll(result->get(), kFileSize);
  return result_size;
}

// static
base::Optional<std::string> SplashScreenCache::GetKeyForStartUrl(
    const GURL& url) {
  base::Optional<std::string> encoded_url = base::GetApplicationKey(url);
  if (!encoded_url) {
    return base::nullopt;
  }

  char path[SB_FILE_MAX_PATH] = {0};
  bool has_cache_dir =
      SbSystemGetPath(kSbSystemPathCacheDirectory, path, SB_FILE_MAX_PATH);
  if (!has_cache_dir) {
    return base::nullopt;
  }

  std::string subpath = "";
  std::string subcomponent = SB_FILE_SEP_STRING + std::string("splash_screen");
  if (SbStringConcat(path, subcomponent.c_str(), SB_FILE_MAX_PATH) >=
      SB_FILE_MAX_PATH) {
    return base::nullopt;
  }
  subpath += "splash_screen";
  subcomponent = SB_FILE_SEP_STRING + *encoded_url;
  if (SbStringConcat(path, subcomponent.c_str(), SB_FILE_MAX_PATH) >=
      SB_FILE_MAX_PATH) {
    return base::nullopt;
  }
  subpath += subcomponent;
  subcomponent = SB_FILE_SEP_STRING + std::string("splash.html");
  if (SbStringConcat(path, subcomponent.c_str(), SB_FILE_MAX_PATH) >
      SB_FILE_MAX_PATH) {
    return base::nullopt;
  }
  subpath += subcomponent;

  return subpath;
}

}  // namespace browser
}  // namespace cobalt
