# Copyright 2020 NullConvergence
#
# 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.

"""This module establishes a connection to the database and
initializes the miners
"""
from py2neo import Graph
from graphrepo.config import Config
from graphrepo.logger import Logger
from graphrepo.singleton import Singleton
from graphrepo.miners import MineManager

LG = Logger()


class Miner(metaclass=Singleton):
  """Miner class - connects to db and initializes miners.
  The miners do the db queries.
  This class is a singleton because it holds the connection
  to Neo4j in self.graph
  """

  def __init__(self):
    """Initializes the properties of this class"""
    self.config = Config()
    self.graph = None
    self.manager = None

  def configure(self, db_url="localhost",
                port=13000, db_user="neo4j",
                db_pwd="neo4j", *args, **kwargs):
    """Sets the application constants"""
    # TODO: validate inputs
    self.config.DB_URL = db_url
    self.config.PORT = port
    self.config.DB_USER = db_user
    self.config.DB_PWD = db_pwd

    self.init_miners()

  def connect(self):
    """Instantiates the connection to Neo4j and stores
    the graph internally.
    Throws exception if the connection can not pe realized
    """
    try:
      self.graph = Graph(host=self.config.DB_URL,
                         user=self.config.DB_USER,
                         password=self.config.DB_PWD,
                         http_port=self.config.PORT)
    except Exception as exc:
      LG.log_and_raise(exc)

  def init_miners(self):
    """This method initializes the miner manager,
    which initializes a team of miners
    """
    self.config.check_config()
    self.check_connection()
    self.manager = MineManager(graph=self.graph)

  def check_connection(self):
    """Checks if there is a db connection and raises
    ReferenceError if not.
    """
    try:
      self.connect()
    except:
      raise ReferenceError("There is no valid "
                           "database connection. Please "
                           "configure and connect first.")
