import sqlite3


DB_PATH = 'bookmarks.db'

SQL_INSERT_BOOKMARK = "INSERT INTO bookmarks VALUES (?,?,?,?,?,?,?,?)"
SQL_UPDATE_BOOKMARK = "UPDATE bookmarks SET {:s} WHERE id=?"

class DBConnectionError(Exception):
    
    def __init__(self, value):
        self.value = value
        
    def __str__(self, value):
        return repr(self.value)
        

class Bookmark(object):
    
    def __init__(self, db_conn, id=None, url=None):
        
        # Make sure the DB connection is valid before doing anything 
        # else
        if not db_conn:
            raise DBConnectionError('Invalid database connection object!')
        
        # Setup internal parameters
        self._db_conn = db_conn
        
        # Setup defaut object data attributes
        self.id = id
        self.url = url
        self.title = ''
        self.description = ''
        self.times_visited = 0
        self.last_visited = 0
        self.last_reachable = 0
        self.deleted = False
        
        # This dict MUST appear after the data attributes, it is used to 
        # record which data attributes are dirty
        self._dirty = {'url': False,
                       'title': False,
                       'description': False,
                       'times_visited': False,
                       'last_visited': False,
                       'last_reachable': False,
                       'deleted': False}        
    
    def __del__(self):
        """ Save any changes to a record before the object is destroyed. """
        # Check if the record is dirty
        if self.record_dirty:
            if self.id:
                # Update existing record
                pass
            else:
                # Insert new record
                self._db_insert()
    
    def __setattr__(self, name, value):
        """ Customize setting data attributes so we can tell which ones
        are dirty.
        """
        
        # Check if the attr is a data attribute then check if the value has 
        # changed. If so, mark the attribute as dirty
        if hasattr(self, '_dirty'):
            if name in self._dirty and getattr(self, name) != value:
                self._dirty[name] = True
                
        # Set the attribute value using the super class's __setattr__ to avoid
        # infinite recursion (recursion joke here)
        super(Bookmark, self).__setattr__(name, value)
        
    def _db_insert(self):
        """ Insert a new bookmark into the database. """
        db = self._db_conn.cursor()
        values = (0, self.url, self.title, self.description, 
                  self.times_visited, self.last_visited, self.last_reachable,
                  self.deleted and '1' or '0')
        db.execute(SQL_INSERT_BOOKMARK, values)
        self._db_conn.commit()
        
        # Reset dirty flags
        for key in self._dirty.keys():
            self._dirty[key] = False
            
    def _db_update(self):
        """ Update an exisitng bookmark row in the database. """
        values = []
        sets = []
        
        # Find dirty data attributes for updating
        for key in self._dirty.keys():
            if self._dirty[key] == False:
                sets.append('{:s}=?'.format(key))
                values.append(getattr(self, key))
                
        if not value or not sets:
            return
        
        # Add the record id as the last value
        values.append(self.id)
        
        # Build full SQL statement then execute it
        sql = SQL_UPDATE_BOOKMARK.format(','.join(sets))
        db = self._db_conn.cursor()
        db.execute(SQL_INSERT_BOOKMARK, values)
        self._db_conn.commit()
        
        print('Updated record')
        
        # Reset dirty flags
        for key in self._dirty.keys():
            self._dirty[key] = False
    
    @property
    def record_dirty(self):
        """ Check if any data attributes are dirty, which indicates the record 
        is dirty.
        """
        return any([val for key, val in self._dirty.items()])
