#!/usr/bin/env python
# -*- coding: utf-8 -*-
# #############################################################
#                                            ..                
#                       ....  ............   ........          
#                     .     .......   .            ....  ..    
#                   .  ... ..   ..   ..    ..   ..... .  ..    
#                   .. .. ....@@@.  ..  .       ........  .    
#              ..  .  .. ..@.@@..@@.  .@@@@@@@   @@@@@@. ....  
#         .@@@@. .@@@@. .@@@@..@@.@@..@@@..@@@..@@@@.... ....  
#       @@@@... .@@@.. @@ @@  .@..@@..@@...@@@.  .@@@@@.    .. 
#     .@@@..  . @@@.   @@.@@..@@.@@..@@@   @@ .@@@@@@..  ..... 
#    ...@@@.... @@@    .@@.......... ........ .....        ..  
#   . ..@@@@.. .         .@@@@.   .. .......  . .............  
#  .   ..   ....           ..     .. . ... ....                
# .    .       ....   ............. .. ...                     
# ..  ..  ...   ........ ...      ...                          
#  ................................                            
#                                                              
# #############################################################
# __init__.py
#
#     Fields: outils pour passer les informations de la base
#     vers les objets python et vice-versa
#
# Auteur: Grégoire Détrez <gdetrez@crans.org>
# Copyright (c) 2008 by www.crans.org
# #############################################################
import re

class baseField(object):
    def __init__(self, name):
        self.name = name

    def _save_field( self, data ):
        return data
    def _load_field( self, data ):
        return str(data)

    def load( self, ldap_data ):
        if ldap_data == None: return None
        return self._load_field( ldap_data[0] )
    def save( self, field_data ):
        return [ self._save_field( field_data )]

class stringField( baseField ):
    pass

class reField( stringField ):
    def __init__( self, name, expr ):
        baseField.__init__(self, name)
        self.expr = re.compile(expr)

    def _save_field(self, field_data):
        if self.expr.match( field_data ):
            return field_data
        else:
            raise ValueError, "Incorect value for field %s" % self.name

class macField( reField ):
    def __init__( self, name ):
        self = reField.__init__(self, name, "^([0-9a-fA-F]{2}:){5}[0-9a-fA-F]{2}$")
    def _save_field( self, data ):
        data = data.lower()
        if not self.expr.match( data ):
            data = re.sub( "[^0-9a-fA-F]", "", data )
            if len(data) == 12:
                data = data[0:2] + ":" + data[2:4] + ":" + data [4:6] + ":" + data[6:8] + ":" + data[8:10] + ":" + data[10:12]
        return reField._save_field( self, data )

class ipField( reField ): 
    def __init__( self, name ):
        self = reField.__init__(self, name, "^(\d{1,3}\.){3}\d{1,3}$")

class emailField( reField ): 
    def __init__( self, name, suffix=None ):
        stringField.__init__( self, name)
        self.expr = re.compile("^(?P<prefix>[\w\+]+)(@(?P<suffix>[\w\.]+\.\w{1,3}))?$" )
        self.suffix = suffix

    def _load_field(self, data):
        if self.suffix:
            m = self.expr.match( data )
            if m.group('suffix'):
                return data
            else:
                return data + u"@" + self.suffix
        else:
            return data

    def _save_field(self, data):
        m = self.expr.match( data )
        if m:
            if self.suffix and  m.group("suffix") == self.suffix:
                    return m.group("prefix")
            return data
        else:
            raise ValueError, "Mail invalid"

                

class loginField( reField ): 
    def __init__( self, name ):
        self = reField.__init__(self, name, "^[a-z]{4,}$")

class listField( baseField ):
    def __init__( self, name, type_field ):
        baseField.__init__(self, name)
        self.type_field = type_field
    def load( self, ldap_data ):
        if ldap_data == None: return []
        return map( self.type_field._load_field, ldap_data )
    def save( self, field_data ):
        return map( self.type_field._save_field, field_data )

class historyField( baseField ):
    pass

class pathField( baseField ):
    pass

class intField( baseField ):
    def _load_field( self, ldap_data ):
        return int( ldap_data )
    def _save_field(self, field_data ):
        return str( field_data )

class booleanField( baseField ):
    def _load_field( self, ldap_data ):
        return ldap_data == 'TRUE'
    def _save_field( self, field_Data ):
        if field_data: return 'TRUE'
        else: return 'FALSE'

class telField( reField ):
    def __init__(self, name ):
        reField.__init__( self, name, "^\d{10}$")
    def _save_field( self, data ):
        return reField._save_field( self, re.sub("[\ \.,]", "", data ) )




if __name__ == "__main__":
    import unittest

    class TestFields(unittest.TestCase):
        def setUp(self):
            pass

        def testBaseField( self ):
            field = baseField( "Un nom" )
            assert field.load(["un test"]) == "un test"
            assert field.save("un test") == ["un test"]

        def testStringField( self ):
            field = stringField( "Un nom" )
            assert field.load(["une string"]) == "une string"
            assert field.save("une string") == ["une string"]

        def testReField( self ):
            field = reField( "Un nom", "^[A-Z][a-z]+$" )
            assert field.load(["Coucou"]) == "Coucou"
            assert field.save("Coucou") == ["Coucou"]
            self.assertRaises(ValueError, field.save, "")
            self.assertRaises(ValueError, field.save, "coucou")
            self.assertRaises(ValueError, field.save, "coucou monde")
            self.assertRaises(ValueError, field.save, "Coucou monde")

        def testMacField( self ):
            field = macField( "Un nom" )
            assert field.load(["00:0f:20:57:6e:81"]) == "00:0f:20:57:6e:81"
            assert field.save("00:0f:20:57:6e:81") == ["00:0f:20:57:6e:81"]
            assert field.save("00:0F:20:57:6E:81") == ["00:0f:20:57:6e:81"]
            assert field.save("000f20576e81") == ["00:0f:20:57:6e:81"]
            assert field.save("00 0f 20 57 6e 81") == ["00:0f:20:57:6e:81"]
            self.assertRaises(ValueError, field.save, "00:0f:20:57:6e:81:34")
            self.assertRaises(ValueError, field.save, "00:0f:20:57:6e:8")
            self.assertRaises(ValueError, field.save, "00:0f:20:57:6e")
            self.assertRaises(ValueError, field.save, "00:0f:20:57:6k:81")

        def testIpField( self ):
            field = ipField( "Un nom" )
            assert field.load(["129.168.0.34"]) == "129.168.0.34"
            assert field.save("129.168.0.34") == ["129.168.0.34"]
            self.assertRaises(ValueError, field.save, "192.16.8")
            self.assertRaises(ValueError, field.save, "192.16.8.2.3")
            self.assertRaises(ValueError, field.save, "192.16.8.e")
            self.assertRaises(ValueError, field.save, "125.34..56")

        def testEmailField( self ):
            field = emailField( "Un email", suffix="crans.org" )
            assert field.load(["toto@exemple.com"]) == "toto@exemple.com"
            assert field.save("toto@exemple.com") == ["toto@exemple.com"]
            assert field.load(["toto@crans.org"]) == "toto@crans.org"
            assert field.load(["toto"]) == "toto@crans.org"
            assert field.save("toto") == ["toto"]
            assert field.save("toto@crans.org") == ["toto"]
            self.assertRaises(ValueError, field.save, "toto@")
            self.assertRaises(ValueError, field.save, "toto@test")
            self.assertRaises(ValueError, field.save, "test.com")
 
        def testLoginField( self ):
            field = loginField( "Un nom" )
            assert field.load(["toto"]) == "toto"
            assert field.save("toto") == ["toto"]
#        def testHistoryField( self ):
#            field = baseField( "Un nom" )
#            assert field.load(["un test"]) == "un test"
#            assert field.save("un test") == ["un test"]
        def testListField( self ):
            field = listField( "Un nom", stringField(None) )
            assert field.load(["un test"]) == ["un test"]
            assert field.load(["un test", "un autre"]) == ["un test", "un autre"]

        def testTelField( self ):
            field = telField( "Un nom" )
            assert field.load(["0606060606"]) == "0606060606"
            assert field.save("0606060606") == ["0606060606"]
            assert field.save("06 060 606 06") == ["0606060606"]
            assert field.save("06 06 06 06 06") == ["0606060606"]
            self.assertRaises(ValueError, field.save, "06060606")
            self.assertRaises(ValueError, field.save, "06060606060606")

    unittest.main()
