/*
 * 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.
 */

#ifndef FRUIT_PROVIDER_DEFN_H
#define FRUIT_PROVIDER_DEFN_H

#include <fruit/impl/storage/injector_storage.h>

// Redundant, but makes KDevelop happy.
#include <fruit/provider.h>

namespace fruit {

template <typename C>
inline Provider<C>::Provider(fruit::impl::InjectorStorage* storage, fruit::impl::InjectorStorage::Graph::node_iterator itr)
  : storage(storage), itr(itr) {
}

template <typename C>
inline C* Provider<C>::get() {
  return storage->getPtr<C>(itr);
}

namespace impl {
namespace meta {

template <typename C>
struct ProviderImplHelper {
  
  template <typename T>
  using CheckGet = Eval<
    If(Not(IsSame(GetClassForType(Type<T>), Type<C>)),
        ConstructError(TypeNotProvidedErrorTag, Type<T>),
    None)>;
};

} // namespace meta
} // namespace impl

template <typename C>
template <typename T>
inline T Provider<C>::get() {
  using E = typename fruit::impl::meta::ProviderImplHelper<C>::template CheckGet<T>;
  (void)typename fruit::impl::meta::CheckIfError<E>::type();
  return storage->template get<T>(itr);
}

template <typename C>
template <typename T>
inline Provider<C>::operator T() {
  return get<T>();
}


} // namespace fruit


#endif // FRUIT_PROVIDER_DEFN_H
