// Copyright 2018 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef ZIRCON_SYSTEM_HOST_FIDL_INCLUDE_FIDL_LIBRARY_H_
#define ZIRCON_SYSTEM_HOST_FIDL_INCLUDE_FIDL_LIBRARY_H_

#include <errno.h>

#include <map>
#include <memory>
#include <set>
#include <string>
#include <utility>
#include <vector>

#include "ast.h"
#include "coded_ast.h"
#include "flat_ast.h"
#include "identifier_table.h"
#include "source_manager.h"
#include "type_shape.h"

namespace fidl {

class Library {
public:
    bool ConsumeFile(std::unique_ptr<ast::File> file);
    bool Resolve();

private:
    bool ConsumeConstDeclaration(std::unique_ptr<ast::ConstDeclaration> const_declaration);
    bool ConsumeEnumDeclaration(std::unique_ptr<ast::EnumDeclaration> enum_declaration);
    bool
    ConsumeInterfaceDeclaration(std::unique_ptr<ast::InterfaceDeclaration> interface_declaration);
    bool ConsumeStructDeclaration(std::unique_ptr<ast::StructDeclaration> struct_declaration);
    bool ConsumeUnionDeclaration(std::unique_ptr<ast::UnionDeclaration> union_declaration);

    bool RegisterTypeName(const flat::Name& name);

    bool ResolveConst(const flat::Const& const_declaration);
    bool ResolveEnum(const flat::Enum& enum_declaration);
    bool ResolveInterface(const flat::Interface& interface_declaration);
    bool ResolveStruct(const flat::Struct& struct_declaration);
    bool ResolveUnion(const flat::Union& union_declaration);

    bool ResolveArrayType(const ast::ArrayType& array_type, TypeShape* out_type_metadata);
    bool ResolveVectorType(const ast::VectorType& vector_type, TypeShape* out_type_metadata);
    bool ResolveStringType(const ast::StringType& string_type, TypeShape* out_type_metadata);
    bool ResolveHandleType(const ast::HandleType& handle_type, TypeShape* out_type_metadata);
    bool ResolveRequestType(const ast::RequestType& request_type, TypeShape* out_type_metadata);
    bool ResolvePrimitiveType(const ast::PrimitiveType& primitive_type,
                              TypeShape* out_type_metadata);
    bool ResolveIdentifierType(const ast::IdentifierType& identifier_type,
                               TypeShape* out_type_metadata);
    bool ResolveType(const ast::Type* type) {
        TypeShape type_metadata;
        return ResolveType(type, &type_metadata);
    }
    bool ResolveType(const ast::Type* type, TypeShape* out_type_metadata);
    bool ResolveTypeName(const ast::CompoundIdentifier* name);
    bool RegisterResolvedType(const flat::Name& name, TypeShape type_metadata);

    bool LookupTypeShape(const flat::Name& name, TypeShape* out_typeshape);

    const coded::Type* LookupIdentifierType(const ast::IdentifierType* identifier_type);

    void MaybeCreateCodingField(std::string field_name, uint32_t offset, const ast::Type* type,
                                std::vector<coded::Field>* fields);

public:
    // TODO(TO-702) Add a validate literal function. Some things
    // (e.g. array indexes) want to check the value but print the
    // constant, say.
    template <typename IntType>
    bool ParseIntegerLiteral(const ast::NumericLiteral* literal, IntType* out_value) {
        if (!literal) {
            return false;
        }
        auto data = literal->location.data();
        std::string string_data(data.data(), data.data() + data.size());
        if (std::is_unsigned<IntType>::value) {
            errno = 0;
            unsigned long long value = strtoull(string_data.data(), nullptr, 0);
            if (errno != 0)
                return false;
            if (value > std::numeric_limits<IntType>::max())
                return false;
            *out_value = static_cast<IntType>(value);
        } else {
            errno = 0;
            long long value = strtoll(string_data.data(), nullptr, 0);
            if (errno != 0) {
                return false;
            }
            if (value > std::numeric_limits<IntType>::max()) {
                return false;
            }
            if (value < std::numeric_limits<IntType>::min()) {
                return false;
            }
            *out_value = static_cast<IntType>(value);
        }
        return true;
    }

    template <typename IntType>
    bool ParseIntegerConstant(const ast::Constant* constant, IntType* out_value) {
        if (!constant) {
            return false;
        }
        switch (constant->kind) {
        case ast::Constant::Kind::Identifier: {
            auto identifier_constant = static_cast<const ast::IdentifierConstant*>(constant);
            auto identifier = identifier_constant->identifier.get();
            // TODO(TO-702) Actually resolve this.
            static_cast<void>(identifier);
            *out_value = static_cast<IntType>(123);
            return true;
        }
        case ast::Constant::Kind::Literal: {
            auto literal_constant = static_cast<const ast::LiteralConstant*>(constant);
            switch (literal_constant->literal->kind) {
            case ast::Literal::Kind::String:
            case ast::Literal::Kind::True:
            case ast::Literal::Kind::False:
            case ast::Literal::Kind::Default: {
                return false;
            }

            case ast::Literal::Kind::Numeric: {
                auto numeric_literal =
                    static_cast<const ast::NumericLiteral*>(literal_constant->literal.get());
                return ParseIntegerLiteral<IntType>(numeric_literal, out_value);
            }
            }
        }
        }
    }

    std::unique_ptr<ast::Identifier> library_name_;

    std::vector<flat::Const> const_declarations_;
    std::vector<flat::Enum> enum_declarations_;
    std::vector<flat::Interface> interface_declarations_;
    std::vector<flat::Struct> struct_declarations_;
    std::vector<flat::Union> union_declarations_;

    // TODO(TO-773) Compute this based on the DAG of aggregates
    // including each other as members.
    std::vector<flat::Name> declaration_order_;

private:
    std::set<flat::Name> registered_types_;
    std::map<flat::Name, TypeShape> resolved_types_;
};

} // namespace fidl

#endif // ZIRCON_SYSTEM_HOST_FIDL_INCLUDE_FIDL_LIBRARY_H_
