import unittest

from Collection import *

class CollectionDBTest(unittest.TestCase):

    def setUp(self):
        self.db = CollectionDB(":memory:")

    def tearDown(self):
        self.db.clear()
        
    def testcreate(self):

        list = self.db.get_names()
        self.assertEqual(len(list), 0)

        # Try invalid type
        try:
            self.db.new_collection("testName", "shouldFail", "invalid")
            self.fail("Adding collection with text type does not fail")
        except:
            pass

        try:
            self.db.new_collection("testName", "shouldFail", None)
            self.fail("Adding collection with NONE type does not fail")
        except:
            pass
        
        # Try invalid ID
        try:
            self.db.new_collection("testName", "shouldFail", id=-1)
            self.fail("Adding collection with ID=-1 does not fail")
        except Exception,e:
            pass
        
        try:
            self.db.new_collection("testName", "shouldFail", id="ivalid")
            self.fail("Adding collection with invalid does not fail")
        except:
            pass

        self.db.clear()
        
        # Try to actually create something
        self.db.new_collection("testName", "testDecription")
        list = self.db.get_names()
        self.assertEqual(len(list), 1)
        self.assertEqual(list, ['Testname'])
        
        # Delete it
        self.db.clear()
        list = self.db.get_names()
        self.assertEqual(len(list), 0)

        self.db.new_collection("testName", "testDecription", type=1)
        list = self.db.get_names()
        self.assertEqual(len(list), 1)
        self.assertEqual(list, ['Testname'])
        
        # Delete it
        self.db.clear()
        list = self.db.get_names()
        self.assertEqual(len(list), 0)

        self.db.new_collection("testName", "testDecription", id=123)
        list = self.db.get_names()
        self.assertEqual(len(list), 1)
        self.assertEqual(list, ['Testname'])
        
        # Delete it
        self.db.clear()
        list = self.db.get_names()
        self.assertEqual(len(list), 0)

        self.db.new_collection("testName", "testDecription", type=1, id=123)
        list = self.db.get_names()
        self.assertEqual(len(list), 1)
        self.assertEqual(list, ['Testname'])
        
        # Should fail to create duplicate
        try:
            self.db.new_collection("testName", "testDecription", type=1, id=123)
            self.fail("Was allowed to create two identical collections")
        except:
            pass
        
        list = self.db.get_names()
        self.assertEqual(len(list), 1)
        self.assertEqual(list, ['Testname'])

        try:
            self.db.new_collection("testName2", "testDecription2", type=2, id=123)
            self.fail("Was allowed to create two collections with same id")
        except:

            pass
        
        list = self.db.get_names()
        self.assertEqual(len(list), 1, "Failed create created something!")
        self.assertEqual(list, ['Testname'])

        # Clean up
        self.db.clear()
        list = self.db.get_names()


    def testinvalidget(self):

        # Invalid get
        try:
            self.db.get_collection()
            self.fail("get_collection without parameters did not fail")
        except:
            pass

        try:
            self.db.get_collection(id=62537)
            self.fail("get_collection does not fail with unknown id")
        except NotFoundException:
            pass

        try:
            self.db.get_collection(name="SomeName")
            self.fail("get_collection does not fail with unknown name")
        except NotFoundException:
            pass

        try:
            self.db.get_collection(id="invalid")
            self.fail("get_collection does not fail with invalid id")
        except:
            pass

    def testget(self):
        
        # Valid
        collection = self.db.new_collection("testName", "testDescription")
        collection2 = self.db.get_collection(name="testName")
        self.assert_(collection, "Could not get created collection")
        self.assertEqual(collection.get_id(), collection2.get_id())
        
        self.assertEqual(collection.get_name(), "Testname")
        self.assertEqual(collection.get_description(), "testDescription")

        id2 = collection.get_id()
        self.assertEqual(collection.get_id(), id2)
        
        collection2 = self.db.get_collection(id=collection.get_id())
        self.assertEqual(collection.get_id(), collection2.get_id())
        self.assertEqual(collection2.get_name(), "Testname")
        self.assertEqual(collection2.get_description(), "testDescription")

    def testremove(self):

        # Invalid
        try:
            self.db.remove_collection()
            self.fail("Accepted remove remove_collection with no arguments")
        except:
            pass

        try:
            self.db.remove_collection(name="nonexistent")
            self.fail("Removed non-existent collection by name")
        except NotFoundException:
            pass

        try:
            self.db.remove_collection(id=123)
            self.fail("Removed non-existent collection by id")
        except NotFoundException:
            pass

        try:
            self.db.remove_collection(id="invalid")
            self.fail("Finds collection by invalid id")
        except Exception:
            pass

        # Now remove properly
        coll = self.db.new_collection("testName", "testDescription")
        self.db.remove_collection(id=coll.get_id())
        list = self.db.get_names()
        self.assertEqual(len(list), 0)
        
        # Remove by name
        coll = self.db.new_collection("testName", "testDescription")
        self.db.remove_collection(name="testName")
        list = self.db.get_names()
        self.assertEqual(len(list), 0)

    def testsmartaddinvalid(self):

        coll = self.db.new_collection("testName", "testDecription")
        valid_url = "http://somewhere/someplace.torrent"
        # INVALID
        try:
            self.db.smart_add("Invalid", valid_url)
            self.fail("Smart_add added invalid")
        except NotFoundException:
            pass
        
        try:
            self.db.smart_add("valid s01e02 therest.torrent", None)
            self.fail("Smart_add added resource without url")
        except Exception:
            pass

        try:
            self.db.smart_add("invalid se02 therest.torrent", valid_url)
            self.fail("Smart_add added resource without season")
        except Exception:
            pass

        try:
            self.db.smart_add("invalid s12e therest.torrent", valid_url)
            self.fail("Smart_add added resource without episode")
        except Exception:
            pass

        try:
            self.db.smart_add("invalid x12 therest.torrent", valid_url)
            self.fail("Smart_add added resource without season (SxE)")
        except Exception:
            pass

        try:
            self.db.smart_add("invalid 12x therest.torrent", valid_url)
            self.fail("Smart_add added resource without episode (SxE)")
        except Exception:
            pass

        try:
            self.db.smart_add("invalid 2007 therest.torrent", valid_url)
            self.fail("Got false positive")
        except NotFoundException:
            pass

        try:
            self.db.smart_add("invalid season therest.torrent", valid_url)
            self.fail("Got false positive")
        except NotFoundException:
            pass

    def testsmartaddvalid(self):

        valid_url = "http://somewhere/someplace.torrent"
        
        # title s1e12
        (c, entry) = self.db.smart_add("Valid s3e01 therest.torrent", valid_url)
        self.assertEqual(c.get_name(), "Valid")
        self.assertEqual(entry, (3, 1, 0, "")) # TODO: Update with type

        (c, entry) = self.db.smart_add("Valid S3e02 therest.torrent", valid_url)
        self.assertEqual(c.get_name(), "Valid")
        self.assertEqual(entry, (3, 2, 0, "")) # TODO: Update with type
        
        (c, entry) = self.db.smart_add("Valid s3E03 therest.torrent", valid_url)
        self.assertEqual(c.get_name(), "Valid")
        self.assertEqual(entry, (3, 3, 0, "")) # TODO: Update with type
            
        (c, entry) = self.db.smart_add("valid s3E04.torrent", valid_url)
        self.assertEqual(c.get_name(), "Valid")
        self.assertEqual(entry, (3, 4, 0, "")) # TODO: Update with type

        (c, entry) = self.db.smart_add("valid s3E05.torrent", valid_url)
        self.assertEqual(c.get_name(), "Valid")
        self.assertEqual(entry, (3, 5, 0, "")) # TODO: Update with type

        # title 1x02
        (c, entry) = self.db.smart_add("valid 4x01.torrent", valid_url)
        self.assertEqual(c.get_name(), "Valid")
        self.assertEqual(entry, (4, 1, 0, "")) # TODO: Update with type

        (c, entry) = self.db.smart_add("valid 4x02 the rest.torrent", valid_url)
        self.assertEqual(c.get_name(), "Valid")
        self.assertEqual(entry, (4, 2, 0, "")) # TODO: Update with type

        # title 103
        (c, entry) = self.db.smart_add("valid 501.torrent", valid_url)
        self.assertEqual(c.get_name(), "Valid")
        self.assertEqual(entry, (5, 1, 0, "")) # TODO: Update with type

        # title 0103
        (c, entry) = self.db.smart_add("valid 0502.torrent", valid_url)
        self.assertEqual(c.get_name(), "Valid")
        self.assertEqual(entry, (5, 2, 0, "")) # TODO: Update with type
        
        # title season X
        (c, entry) = self.db.smart_add("valid Season 6 complete.torrent", valid_url)
        self.assertEqual(c.get_name(), "Valid")
        self.assertEqual(entry, (6, 0, 0, "")) # TODO: Update with type

        # title season X
        (c, entry) = self.db.smart_add("valid Season7", valid_url)
        self.assertEqual(c.get_name(), "Valid")
        self.assertEqual(entry, (7, 0, 0, "")) # TODO: Update with type

        # Quality
        (c, entry) = self.db.smart_add("valid s3E05 720i.torrent", valid_url)
        self.assertEqual(c.get_name(), "Valid")
        self.assertEqual(entry, (3, 5, 0, "720i")) # TODO: Update with type

        (c, entry) = self.db.smart_add("valid s3E05 720p ROXOR.torrent", valid_url)
        self.assertEqual(c.get_name(), "Valid")
        self.assertEqual(entry, (3, 5, 0, "720p")) # TODO: Update with type

        (c, entry) = self.db.smart_add("valid s3E05 1080i.torrent", valid_url)
        self.assertEqual(c.get_name(), "Valid")
        self.assertEqual(entry, (3, 5, 0, "1080i")) # TODO: Update with type

        (c, entry) = self.db.smart_add("valid s3E05 1080p.torrent", valid_url)
        self.assertEqual(c.get_name(), "Valid")
        self.assertEqual(entry, (3, 5, 0, "1080p")) # TODO: Update with type


class CollectionTest(unittest.TestCase):

    testSeason1 = [("1", "s1entry1", "First entry, first season", "url1", 1, 1, 0, "", None, 123456),
                   ("2", "s1entry2", "Second entry, first season", "url2", 1, 2, 0, "", None, 123456),
                   ("3", "s1entry3", "Third entry, first season", "url3", 1, 3, 0, "", None, 123456)]

    testSeason2 = [("4", "s2entry1", "First entry, second season", "url4", 2, 1, 0, "720p", None, 123456),
                   ("5", "s2entry2", "Second entry, second season", "url5", 2, 2, 0, "720p", None, 123456),
                   ("6", "s2entry3", "Third entry, second season", "url6", 2, 3, 0, "720p", None, 123456),
                   ("7", "s2entry3 dupe", "Third entry, second season", "url7", 2, 3, 0, "720p", None, 123456)]

    def setUp(self):
        self.db = CollectionDB(":memory:")

        self.coll_id = self.db.new_collection("testCollection",
                                              "testDescription").get_id()
        self.assert_(self.coll_id != 0, "Failed to set up test collection")

    def testinvalidcreate(self):

        coll = self.db.get_collection(id=self.coll_id)
        self.assert_(coll, "Missing test collection")

        try:
            coll.add_entry(None, None, None, None)
            self.fail("Allowed 'None' as all parameters")
        except:
            pass

        try:
            coll.add_entry(None, "elemName", "elemDescription", "elemUrl")
            self.fail("Allowed NONE as id")
        except:
            pass
        
        try:
            coll.add_entry("123", None, "elemDescription", "elemUrl")
            self.fail("Allowed NONE as name")
        except:
            pass
        
        try:
            coll.add_entry("123", "elemName", None, "elemUrl")
            self.fail("Allowed NONE as description")
        except:
            pass

        try:
            coll.add_entry("123", "elemName", "elemDescription", None)
            self.fail("Allowed NONE as URL")
        except:
            pass
        
        try:
            coll.add_entry("123", "elemName", "elemDecription", "elemUrl", major="invalid")
            self.fail("Allowed invalid major")
        except:
            pass
        
        try:
            coll.add_entry("123", "elemName", "elemDecription", "elemUrl", minor="invalid")
            self.fail("Allowed invalid minor")
        except:
            pass
        
        try:
            coll.add_entry("123", "elemName", "elemDecription", "elemUrl", type="invalid")
            self.fail("Allowed invalid type")
        except:
            pass

    def testcreate(self):

        coll = self.db.get_collection(id=self.coll_id)
        self.assert_(coll, "Missing test collection")

        # Add season 1
        for (id, name, desc, url, major, minor, type, quality, ts, size) in self.testSeason1:
            coll.add_entry(id, name, desc, url, major, minor, type, quality, ts, size)

        # Find season 1
        season1 = coll.get_entries()
        self.assertEqual(self.testSeason1, season1)

        for entry  in self.testSeason1:
            (id, name, desc, url, major, minor, type, quality, ts, size) = entry
            entry2 = coll.get_entry(id=id)
            self.assert_(entry2, "Missing entry %s"%id)
            self.assertEquals(entry, entry2)
        
        # Add season 2
        for (id, name, desc, url, major, minor, type, quality, ts, size) in self.testSeason2:
            coll.add_entry(id, name, desc, url, major, minor, type, quality, ts, size)

        # Find season 1
        season1 = coll.get_entries(major=1)
        self.assertEqual(self.testSeason1, season1)

        for entry  in self.testSeason1:
            (id, name, desc, url, major, minor, type, quality, ts, size) = entry
            entry2 = coll.get_entry(id=id)
            self.assert_(entry2, "Missing entry %s"%id)
            self.assertEquals(entry, entry2)

        # Find season 2
        season2 = coll.get_entries(major=2)
        self.assertEqual(self.testSeason2, season2)

        for entry in self.testSeason2:
            (id, name, desc, url, major, minor, type, quality, ts, size) = entry
            entry2 = coll.get_entry(id=id)
            self.assert_(entry2, "Missing entry %s"%id)
            self.assertEqual(entry, entry2)

        # Find one and one
        for entry in self.testSeason1 + self.testSeason2:
            (id, name, desc, url, major, minor, type, quality, ts, size) = entry
            list = coll.get_entries(major=major, minor=minor, dupes=False)
            self.assertEqual(len(list), 1)
            entry2 = list[0]
            if name != "s2entry3 dupe":
                self.assert_(entry2, "Missing entry %s"%id)
                self.assertEqual(entry, entry2)

        # Do not fetch duplicates
        season2 = coll.get_entries(major=2, dupes=False)
        self.assertEqual(len(season2), 3)

        # Find based on quality
        season2 = coll.get_entries(quality="720P")
        self.assertEqual(self.testSeason2, season2)
        
        empty = coll.get_entries(quality="1080p")
        self.assertEqual(empty, [])
        
        # Empty string means low quality...  TODO: Fix?
        season1 = coll.get_entries(quality="")
        self.assertEqual(self.testSeason1, season1)
        
        # Find reversed
        season1 = coll.get_entries(major=1, reverse=True)
        rev = self.testSeason1[:]
        rev.reverse()
        self.assertEqual(rev, season1)

    def testsetget(self):

        coll = self.db.get_collection(id=self.coll_id)
        self.assert_(coll, "Missing test collection")

        self.assertEqual(coll.get_name(), "Testcollection")
        self.assertEqual(coll.get_description(), "testDescription")

        # Invalid
        try:
            coll.set_name(None)
            self.fail("Allow name to be set to None")
        except:
            pass
        
        try:
            coll.set_description(None)
            self.fail("Allow description to be set to None")
        except:
            pass
        
        coll.set_name("newName")
        self.assertEqual(coll.get_name(), "newName")
        
        coll.set_description("newDescription")
        self.assertEqual(coll.get_name(), "newName")
        self.assertEqual(coll.get_description(), "newDescription")
        



if __name__ == "__main__":

    print "Testing the Collection classes"

    unittest.main()

    print "All done"
