  logger.exception("""
#
#Please install geopy.
#$ sudo pip install geopy
#  """)
#  exit()

#else:
#  GEOLOCATOR = Nominatim()


from datetime import datetime


# For the time being, we'll be doing simple plaintext passwords. However, this
#  will need to be changed once this system is fully up and running.
class User(db.Model):
  __tablename__ = "user"
  id = db.Column(db.Integer, primary_key=True)
  firstname = db.Column(db.String(80))
  lastname = db.Column(db.String(80))
  username = db.Column(db.String(80), unique=True, nullable=False)
  email = db.Column(db.String(120), unique=True, nullable=False)
  password = db.Column(db.String(120), nullable=False)
  latitude = db.Column(db.Float)
  longitude = db.Column(db.Float)

  def __init__(self, f, l, email, password, lat, lon):
    self.firstname = f
    self.lastname = l
    self.username = "{0} {1}".format(f, l)
    self.email = email
    self.password = password
    self.latitude = lat
    self.longitude = lon

  def getCityInfo(self):
    """
    try:
      location = GEOLOCATOR.reverse(
        query="{0.latitude}, {0.longitude}".format(self),
        exactly_one=True,
      )
      city = location.raw['address']['city']
      state = location.raw['address']['state']
    except:
      logging.exception("Something went wrong reverse looking up lat-longs"
                        " into a city and state combo.")
      city = "<private>"
      state = "Missouri"

    return "{0}, {1}".format(city, state)
    """
    return "Rolla, MO"

  def __repr__(self):
    return "<{0} at ({1}, {2})>".format(
      self.username,
      self.latitude,
      self.longitude,
    )


class ListedItem(db.Model):
  __tablename__ = "listed_item"
  id = db.Column(db.Integer, primary_key=True)

  # This is the number of cents one wants to sell.
  #  Divide by 100 to show dollar amount.
  daily_rate = db.Column(db.Integer, nullable=False)
  is_available = db.Column(db.Boolean, nullable=False)

  owner_id = db.Column(db.Integer, db.ForeignKey('user.id'))
  owner = db.relationship(
    'User',
    backref=db.backref('items', lazy='dynamic'),
  )

  item_type_id = db.Column(db.Integer, db.ForeignKey('category.id'))
  item_type = db.relationship(
    'Category',
    backref=db.backref('listed_items', lazy='dynamic'),
  )

  def __init__(self, rate, owner, item_type):
    self.daily_rate = rate
    self.owner = owner
    self.item_type = item_type
    self.is_available = True

  def requestToRent(self, rentee, duration):
    request = RequestToRent(
      listed_item=self,
      duration_of_rent=duration,
      rentee=rentee,
    )
    return request

  def __repr__(self):
    return ("<{4}{0} (item #{1}) from {2} rated at"
            " ${3:,.2f} daily>".format(
      self.item_type.name,
      self.id,
      self.owner.username,
      float(self.daily_rate)/100,
      "" if self.is_available else "UNAVAILABLE: ",
    ))


class Category(db.Model):
  __tablename__ = "category"
  id = db.Column(db.Integer, primary_key=True)
  name = db.Column(db.String(80), nullable=False)
  image_url = db.Column(db.String(120))

  # Might be more efficient to list children via foreign key and
  #  parent via backref.
  parent_id = db.Column(db.Integer, db.ForeignKey('category.id'))
  parent = db.relationship(
    'Category',
    remote_side=id,
    backref=db.backref('children', lazy='dynamic'),
  )

  def __init__(self, name, image_url=None, parent=None):
    self.name = name
    self.image_url = image_url
    self.parent = parent

  def listMyItem(self, owner, daily_rate):
    # The Category needs to be a leaf category.
    if self.children.count() == 0:
      logger.debug("#"*80)
      logger.info("New item listed!")
      l = ListedItem(
        rate=daily_rate, 
        owner=owner,
        item_type=self,
      )
      logger.info(l)
      logger.debug("#"*80)
      return l

    else:
      raise Exception("An item cannot be listed as an vague item type."
                      " Please choose the most descriptive item category"
                      " available.")

  def __repr__(self):
    if self.parent == None:
      return self.name

    else:
      return "{0} > {1}".format(self.parent, self.name)


class RequestToRent(db.Model):
  __tablename__ = "request_to_rent"
  id = db.Column(db.Integer, primary_key=True)
  request_created_timestamp = db.Column(db.DateTime, nullable=False)
  #days_of_rent = db.Column(db.Integer, nullable=False)
  duration_of_rent = db.Column(db.Interval, nullable=False)

  listed_item_id = db.Column(db.Integer, db.ForeignKey('listed_item.id'))
  listed_item = db.relationship(
    'ListedItem',
    backref=db.backref('requests', lazy='dynamic'),
  )
  rentee_id = db.Column(db.Integer, db.ForeignKey('user.id'))
  rentee = db.relationship(
    'User',
    backref=db.backref('requests', lazy='dynamic'),
  )

  def __init__(self, listed_item, duration_of_rent, rentee):
    self.request_created_timestamp = datetime.utcnow()
    self.listed_item = listed_item
    self.rentee = rentee
    self.duration_of_rent = duration_of_rent

  def suggestPickupTimes(self, available_from, available_until, location):
    return ProposedPickupTime(
      request=self,
      meetup_time=available_from,
      available_until=available_until,
      location=location,
    )

  def __repr__(self):
    return (
    "<{0} requested a {1} (item #{2}) at {3} for {4}\n"
    "{5} will need to choose pickup times before request is accepted>".format(
      self.rentee.username,
      self.listed_item.item_type.name,
      self.listed_item.id,
      self.request_created_timestamp,
      self.duration_of_rent,
      self.listed_item.owner.username,
    ))


class ProposedPickupTime(db.Model):
  __tablename__ = "proposed_pickup_time"
  id = db.Column(db.Integer, primary_key=True)
  proposed_meetup_time = db.Column(db.DateTime, nullable=False)
  owner_available_until = db.Column(db.DateTime, nullable=False)
  location = db.Column(db.String(120), nullable=False)

  request_id = db.Column(db.Integer, db.ForeignKey('request_to_rent.id'))
  request = db.relationship(
    'RequestToRent',
    backref=db.backref(
      "pickup_times",
