"""
  @file   inv/api/methods.py
  @author Brian Kim
  @brief  this module defines the list of api methods supported by inv
          as well as the authorization scheme of user groups
"""

from model import *
from datetime import datetime

# definition of the methods
def save():
  db.session.commit()

def list_obj2dict(x):
  """
   converts a list of model objects to dictionaries
  """
  return [dict(y) for y in x]
  
"""
 User methods
"""

def read_user(uid):
  """
   @param id int the id of the user
  """
  return User.query.filter_by(uid=uid).first()

def read_user_all():
  return list_obj2dict(User.query.filter_by().all())

def delete_user(uid):
  u = User.query.filter_by(uid=uid).first()
  if not u: return False
  db.session.delete(u)
  save()
  return True

"""
 Location methods
"""

def create_building(x):
  """
   @param x str the name of the building
   @return y LocationBuilding the object that was placed into the db or None for failure
  """
  y = None
  exists = find_building(x) 
  if not exists:
    y = LocationBuilding(x)
    db.session.add(y)
    save()
  return y

def find_building(name):
  """
   @param x str the name of the building
   @return y LocationBuilding or None 
  """
  return LocationBuilding.query.filter_by(name=name).first()

def read_building(x):
  """
   @param x str the id of the building
   @return y LocationBuilding or None 
  """
  return LocationBuilding.query.filter_by(id=x).first()

def read_building_all():
  """
   @return list of dict representation of LocationBuildings
  """
  return list_obj2dict(LocationBuilding.query.filter_by().all())
  
def update_building(id,x):
  """
   @param id int the id of the building
   @param x str the new name of the building
   @return building LocationBuilding or None
  """
  building = LocationBuilding.query.filter_by(id=id).first()
  if not building: return None
  building.name = x
  save()
  return building

def delete_building(id):
  """
   @param id int the id of the building to delete
   @return bool True for success, False for failure
  """
  building = LocationBuilding.query.filter_by(id=id).first()
  if not building: return False
  db.session.delete(building)
  save()
  return True

def count_all_location(by):
  return 0
   
def count_location(by,id):
  return 0
  
def create_location(x):
  """
  @param x dict key/value pairs of the location to add
  @return y Location the object that was placed into the db or None for failure
  """
  y = None
  exists = Location.query.filter(Location.building.has(name=x['building']),Location.room.is_(x['room'])).first()
  if not exists:
    # get the values
    building = find_building(x['building'])
    room = x['room']
    # create a building entry if it doesn't exist
    if not building:
      building = create_building(x['building'])
    # create and add the location
    y = Location(building,room)
    db.session.add(y)
    save()
  return y

def read_location_all():
  x = Location.query.filter_by().all()
  return list_obj2dict(x)

def read_location(id):
  return Location.query.filter_by(id=id).first()

def update_location(id,x):
  """
   @param id int the id of the building
   @param x dict key/value pairs of the updated values
   @return loc Location or None
  """
  loc = read_location(id)
  if not loc: return None
  # building name
  new_build = x.get('building')
  if loc.building.name != new_build:
    build = find_building(new_build)
    build = create_building(new_build) if not build else build
    loc.building = build
  # room number
  loc.room = x.get('room')
  save()
  return loc

def delete_location(id):
  """
   @param id int the id of the location to delete
   @return bool True for success, False for failure
  """
  loc = Location.query.filter_by(id=id).first()
  if not loc: return False
  db.session.delete(loc)
  save()
  return True

"""
 Item methods
"""

def create_category(x):
  """
   @param x str the name of the building
   @return y ItemCategory the object that was placed into the db or None for failure
  """
  y = None
  exists = find_category(x) 
  if not exists:
    y = ItemCategory(x)
    db.session.add(y)
    save()
  return y

def find_category(name):
  """
   @param x str the name of the item category
   @return y ItemCategory or None 
  """
  return ItemCategory.query.filter_by(name=name).first()

def read_category(x):
  """
   @param x str the name of the category
   @return y ItemCategory or None 
  """
  return ItemCategory.query.filter_by(id=x).first()

def read_category_all():
  """
   @return list of dict representation of all item categories
  """
  return list_obj2dict(ItemCategory.query.filter_by().all())

def update_category(id,x):
  """
   @param id int the id of the category
   @param x str the new name of the category
   @return cat Category or None
  """
  cat = Category.query.filter_by(id=id).first()
  if not cat: return None
  # category name
  cat.name = x.get('name')
  save()
  return cat

def delete_category(id):
  """
   @param id int the id of the category to delete
   @return bool True for success, False for failure
  """
  cat = Category.query.filter_by(id=id).first()
  if not cat: return False
  db.session.delete(cat)
  save()
  return True
  
def create_manufacturer(x):
  """
   @param x str the name of the building
   @return y LocationBuilding the object that was placed into the db or None for failure
  """
  y = None
  exists = find_manufacturer(x) 
  if not exists:
    y = ItemManufacturer(x)
    db.session.add(y)
    save()
  return y

def find_manufacturer(name):
  """
   @param x str the name of the item manufacturer
   @return y ItemManufacturer or None 
  """
  return ItemManufacturer.query.filter_by(name=name).first()

def read_manufacturer(x):
  """
   @param x str the id of the manufacturer
   @return y ItemManufacturer or None 
  """
  return ItemManufacturer.query.filter_by(id=x).first()

def read_manufacturer_all():
  """
   @return list of dict representation of all item manufacturers
  """
  return list_obj2dict(ItemManufacturer.query.filter_by().all())

def update_manufacturer(id,x):
  """
   @param id int the id of the manufacturer
   @param x str the new name of the manufacturer
   @return man ItemManufacturer or None
  """
  man = ItemManufacturer.query.filter_by(id=id).first()
  if not man: return None
  # manufacturer name
  man.name = x.get('name')
  save()
  return man

def delete_manufacturer(id):
  """
   @param id int the id of the manufacturer to delete
   @return bool True for success, False for failure
  """
  man = ItemManufacturer.query.filter_by(id=id).first()
  if not man: return False
  db.session.delete(man)
  save()
  return True

def item_exists(x):
  category = Item.category.has(name=x['category'])
  manufacturer = Item.manufacturer.has(name=x['manufacturer'])
  model = Item.model.is_(x['model'])
  return Item.query.filter(category,manufacturer,model).first()

def create_item(x):
  """
   @param x dict key/value pairs of the item to add