/*
 * Copyright 2014 Google Inc. 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.
 */

#define IN_FRUIT_CPP_FILE

#include <cstdlib>
#include <memory>
#include <vector>
#include <iostream>
#include <algorithm>
#include <fruit/impl/util/type_info.h>

#include <fruit/impl/injector/injector_storage.h>
#include <fruit/impl/data_structures/semistatic_graph.templates.h>
#include <fruit/impl/normalized_component_storage/binding_normalization.h>
#include <fruit/impl/component_storage/component_storage.h>
#include <fruit/impl/normalized_component_storage/binding_normalization.templates.h>

using std::cout;
using std::endl;

using namespace fruit::impl;

namespace fruit {
namespace impl {

void InjectorStorage::fatal(const std::string& error) {
  std::cerr << "Fatal injection error: " << error << std::endl;
  exit(1);
}

// LCOV_EXCL_START
namespace {
  template <typename Id, typename Value>
  struct DummyNode {
    Id getId() {
      return Id();
    }
    bool isTerminal() {
      return false;
    }
    Id* getEdgesBegin() {
      return nullptr;
    }
    Id* getEdgesEnd() {
      return nullptr;
    }
    Value getValue() {
      return Value();
    }
  };
}
// LCOV_EXCL_STOP

InjectorStorage::InjectorStorage(
    ComponentStorage&& component,
    const std::vector<TypeId, ArenaAllocator<TypeId>>& exposed_types,
    MemoryPool& memory_pool)
  : normalized_component_storage_ptr(
      new NormalizedComponentStorage(
          std::move(component),
          exposed_types,
          memory_pool,
          NormalizedComponentStorage::WithPermanentCompression())),
    allocator(normalized_component_storage_ptr->fixed_size_allocator_data),
    bindings(normalized_component_storage_ptr->bindings,
             (DummyNode<TypeId, NormalizedBinding>*)nullptr,
             (DummyNode<TypeId, NormalizedBinding>*)nullptr,
             memory_pool),
    multibindings(std::move(normalized_component_storage_ptr->multibindings)) {

#ifdef FRUIT_EXTRA_DEBUG
  bindings.checkFullyConstructed();
#endif
}

InjectorStorage::InjectorStorage(const NormalizedComponentStorage& normalized_component,
                                 ComponentStorage&& component,
                                 MemoryPool& memory_pool) {

  FixedSizeAllocator::FixedSizeAllocatorData fixed_size_allocator_data;
  using new_bindings_vector_t = std::vector<ComponentStorageEntry, ArenaAllocator<ComponentStorageEntry>>;
  new_bindings_vector_t new_bindings_vector =
      new_bindings_vector_t(ArenaAllocator<ComponentStorageEntry>(memory_pool));

  BindingNormalization::normalizeBindingsAndAddTo(
      std::move(component).release(),
      memory_pool,
      normalized_component,
      fixed_size_allocator_data,
      new_bindings_vector,
      multibindings);

  allocator = FixedSizeAllocator(fixed_size_allocator_data);

  bindings = Graph(normalized_component.bindings,
                   BindingDataNodeIter{new_bindings_vector.begin()},
                   BindingDataNodeIter{new_bindings_vector.end()},
                   memory_pool);
#ifdef FRUIT_EXTRA_DEBUG
  bindings.checkFullyConstructed();
#endif
}

InjectorStorage::~InjectorStorage() {
}

void InjectorStorage::ensureConstructedMultibinding(
    NormalizedMultibindingSet& multibinding_set) {
  for (NormalizedMultibinding& multibinding : multibinding_set.elems) {
    if (!multibinding.is_constructed) {
      multibinding.object = multibinding.create(*this);
      multibinding.is_constructed = true;
    }
  }
}

void* InjectorStorage::getMultibindings(TypeId typeInfo) {
  NormalizedMultibindingSet* multibinding_set = getNormalizedMultibindingSet(typeInfo);
  if (multibinding_set == nullptr) {
    // Not registered.
    return nullptr;
  }
  return multibinding_set->get_multibindings_vector(*this).get();
}

void InjectorStorage::eagerlyInjectMultibindings() {
  for (auto& typeInfoInfoPair : multibindings) {
    typeInfoInfoPair.second.get_multibindings_vector(*this);
  }
}

} // namespace impl
// We need a LCOV_EXCL_BR_LINE below because for some reason gcov/lcov think there's a branch there.
} // namespace fruit LCOV_EXCL_BR_LINE
