/*
 * Copyright (c) 2017 Cisco and/or its affiliates.
 * 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 "vom/interface_span.hpp"
#include "vom/interface_span_cmds.hpp"
#include "vom/singular_db_funcs.hpp"

namespace VOM {
/**
 * A DB of all interface_span config
 */
singular_db<interface_span::key_t, interface_span> interface_span::m_db;

interface_span::event_handler interface_span::m_evh;

interface_span::interface_span(const interface& itf_from,
                               const interface& itf_to,
                               interface_span::state_t state)
  : m_itf_from(itf_from.singular())
  , m_itf_to(itf_to.singular())
  , m_state(state)
  , m_config(true)
{
}

interface_span::interface_span(const interface_span& o)
  : m_itf_from(o.m_itf_from)
  , m_itf_to(o.m_itf_to)
  , m_state(o.m_state)
  , m_config(o.m_config)
{
}

interface_span::~interface_span()
{
  sweep();

  // not in the DB anymore.
  m_db.release(make_pair(m_itf_from->key(), m_itf_to->key()), this);
}

void
interface_span::sweep()
{
  if (m_config) {
    HW::enqueue(new interface_span_cmds::unconfig_cmd(
      m_config, m_itf_from->handle(), m_itf_to->handle()));
  }
  HW::write();
}

void
interface_span::dump(std::ostream& os)
{
  db_dump(m_db, os);
}

void
interface_span::replay()
{
  if (m_config) {
    HW::enqueue(new interface_span_cmds::config_cmd(
      m_config, m_itf_from->handle(), m_itf_to->handle(), m_state));
  }
}

std::string
interface_span::to_string() const
{
  std::ostringstream s;
  s << "Itf Span-config:"
    << " itf-from:" << m_itf_from->to_string()
    << " itf-to:" << m_itf_to->to_string() << " state:" << m_state.to_string();

  return (s.str());
}

void
interface_span::update(const interface_span& desired)
{
  if (!m_config) {
    HW::enqueue(new interface_span_cmds::config_cmd(
      m_config, m_itf_from->handle(), m_itf_to->handle(), m_state));
  }
}

std::ostream&
operator<<(std::ostream& os, const interface_span::key_t& key)
{
  os << "[" << key.first << ", " << key.second << "]";

  return (os);
}

std::shared_ptr<interface_span>
interface_span::find_or_add(const interface_span& temp)
{
  return (m_db.find_or_add(
    make_pair(temp.m_itf_from->key(), temp.m_itf_to->key()), temp));
}

std::shared_ptr<interface_span>
interface_span::singular() const
{
  return find_or_add(*this);
}

interface_span::event_handler::event_handler()
{
  OM::register_listener(this);
  inspect::register_handler({ "itf-span" }, "interface span configurations",
                            this);
}

void
interface_span::event_handler::handle_replay()
{
  m_db.replay();
}

void
interface_span::event_handler::handle_populate(const client_db::key_t& key)
{
  std::shared_ptr<interface_span_cmds::dump_cmd> cmd =
    std::make_shared<interface_span_cmds::dump_cmd>();

  HW::enqueue(cmd);
  HW::write();

  for (auto& record : *cmd) {
    auto& payload = record.get_payload();

    std::shared_ptr<interface> itf_from =
      interface::find(payload.sw_if_index_from);
    std::shared_ptr<interface> itf_to = interface::find(payload.sw_if_index_to);

    interface_span itf_span(*itf_from, *itf_to,
                            state_t::from_int(payload.state));

    VOM_LOG(log_level_t::DEBUG) << "span-dump: " << itf_from->to_string()
                                << itf_to->to_string()
                                << state_t::from_int(payload.state).to_string();

    /*
 * Write each of the discovered interfaces into the OM,
 * but disable the HW Command q whilst we do, so that no
 * commands are sent to VPP
 */
    OM::commit(key, itf_span);
  }
}

dependency_t
interface_span::event_handler::order() const
{
  return (dependency_t::BINDING);
}

void
interface_span::event_handler::show(std::ostream& os)
{
  db_dump(m_db, os);
}

const interface_span::state_t interface_span::state_t::DISABLED(0, "disable");
const interface_span::state_t interface_span::state_t::RX_ENABLED(1,
                                                                  "rx-enable");
const interface_span::state_t interface_span::state_t::TX_ENABLED(2,
                                                                  "tx-enable");
const interface_span::state_t interface_span::state_t::TX_RX_ENABLED(
  3,
  "tx-rx-enable");

interface_span::state_t::state_t(int v, const std::string& s)
  : enum_base<interface_span::state_t>(v, s)
{
}

interface_span::state_t
interface_span::state_t::from_int(uint8_t i)
{
  switch (i) {
    case 0:
      return interface_span::state_t::DISABLED;
      break;
    case 1:
      return interface_span::state_t::RX_ENABLED;
      break;
    case 2:
      return interface_span::state_t::TX_ENABLED;
      break;
    case 3:
    default:
      break;
  }

  return interface_span::state_t::TX_RX_ENABLED;
}
}

/*
 * fd.io coding-style-patch-verification: ON
 *
 * Local Variables:
 * eval: (c-set-style "mozilla")
 * End:
 */
