// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// Mobius Forensic Toolkit
// Copyright (C) 2008,2009,2010,2011,2012,2013,2014,2015,2016,2017,2018 Eduardo Aguiar
//
// This program is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by the
// Free Software Foundation; either version 2, or (at your option) any later
// version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
// Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
#include "hash.h"
#include <mobius/database/database.h>

namespace mobius
{
namespace turing
{
mobius::database::database get_database ();

// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
//! \brief constructor
//! \param type hash type
//! \param value hash value
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
hash::hash (std::int64_t uid)
  : uid_ (uid)
{
}

// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
//! \brief set password
//! \param password password
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
void
hash::set_password (const std::string& password)
{
  _load_data ();

  auto db = get_database ();

  auto stmt = db.new_statement (
                "UPDATE hash "
                   "SET password = ?, "
                       "password_status = ?, "
                       "password_min_size = ?, "
                       "password_max_size = ? "
                 "WHERE uid = ?");

  stmt.bind (1, password);
  stmt.bind (2, static_cast <int> (password_status::found));
  stmt.bind (3, static_cast <int> (password.length ()));
  stmt.bind (4, static_cast <int> (password.length ()));
  stmt.bind (5, uid_);
  stmt.execute ();

  password_ = password;
  password_status_ = password_status::found;
}

// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
//! \brief load hash data on demand
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
void
hash::_load_data () const
{
  if (!data_loaded_)
    {
      auto db = get_database ();

      auto stmt = db.new_statement (
                    "SELECT * "
                      "FROM hash "
                     "WHERE uid = ?");

      stmt.bind (1, uid_);

      if (stmt.fetch_row ())
        {
          type_ = stmt.get_column_string (1);
          value_ = stmt.get_column_string (2);
          password_ = stmt.get_column_string (3);
          password_min_size_ = stmt.get_column_int (4);

          if (stmt.is_column_null (5))
            password_max_size_ = -1;
          else
            password_max_size_ = stmt.get_column_int (5);

          password_status_ = hash::password_status (stmt.get_column_int (6));
        }

      data_loaded_ = true;
    }
}

// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
//! \brief load hash arguments on demand
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
void
hash::_load_args () const
{
  if (!args_loaded_)
    {
      auto db = get_database ();

      auto stmt = db.new_statement (
                    "SELECT * "
                      "FROM hash_args "
                     "WHERE uid_hash = ?");

      stmt.bind (1, uid_);

      while (stmt.fetch_row ())
        {
          auto name = stmt.get_column_string (2);
          auto value = stmt.get_column_string (3);
          args_[name] = value;
        }

      args_loaded_ = true;
    }
}

// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
//! \brief check if argument exists
//! \param name argument name
//! \return true/false
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
bool
hash::has_argument (const std::string& name) const
{
  _load_args ();
  return args_.find (name) != args_.end ();
}

// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
//! \brief get argument value
//! \param name argument name
//! \return argument value
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
std::string
hash::get_argument (const std::string& name) const
{
  _load_args ();
  std::string value;

  auto iter = args_.find (name);

  if (iter != args_.end ())
    value = iter->second;

  return value;
}

// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
//! \brief set argument value
//! \param name argument name
//! \param value argument value
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
void
hash::set_argument (const std::string& name, const std::string& value)
{
  _load_args ();

  auto db = get_database ();

  if (has_argument (name))
    {
      auto stmt = db.new_statement (
                    "UPDATE hash_args "
                       "SET value = ? "
                     "WHERE uid_hash = ? "
                       "AND name = ?");
      stmt.bind (1, value);
      stmt.bind (2, uid_);
      stmt.bind (3, name);
      stmt.execute ();
    }

  else
    {
      auto stmt = db.new_statement (
              "INSERT INTO hash_args "
                   "VALUES (NULL, ?, ?, ?)");
      stmt.bind (1, uid_);
      stmt.bind (2, name);
      stmt.bind (3, value);
      stmt.execute ();
    }

  args_[name] = value;
}

// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
//! \brief remove argument
//! \param name argument name
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
void
hash::remove_argument (const std::string& name)
{
  _load_args ();

  if (has_argument (name))
    {
      auto db = get_database ();

      auto stmt = db.new_statement (
            "DELETE FROM hash_args "
                  "WHERE uid_hash = ? "
                    "AND name = ?");

      stmt.bind (1, uid_);
      stmt.bind (2, name);
      stmt.execute ();

      args_.erase (name);
    }
}

} // namespace turing
} // namespace mobius
