#!/usr/bin/env python2

import time
from canari.xmltools.oxml import MaltegoElement, fields as fields_


__author__ = 'Nadeem Douba'
__copyright__ = 'Copyright 2012, Canari Project'
__credits__ = []

__license__ = 'GPL'
__version__ = '0.3'
__maintainer__ = 'Nadeem Douba'
__email__ = 'ndouba@gmail.com'
__status__ = 'Development'

__all__ = [
    'TransformAdapter',
    'VisibilityType',
    'BuiltInTransformSets',
    'Set',
    'Transform',
    'TransformSet',
    'InputConstraint',
    'OutputEntity',
    'InputEntity',
    'PropertyType',
    'TransformProperty',
    'TransformPropertySetting',
    'CmdLineTransformProperty',
    'CmdLineTransformPropertySetting',
    'CmdParmTransformProperty',
    'CmdParmTransformPropertySetting',
    'CmdCwdTransformProperty',
    'CmdCwdTransformPropertySetting',
    'CmdDbgTransformProperty',
    'CmdDbgTransformPropertySetting',
    'TransformSettings',
    'Protocol',
    'AuthenticationType',
    'Authentication',
    'MaltegoServer',
    'EntityCategory',
    'attr',
    'fileobject',
    'attributes',
    'Properties',
    'MaltegoTransform'
]

class TransformAdapter(object):
    Local = 'com.paterva.maltego.transform.protocol.v2.LocalTransformAdapterV2'
    Remote = 'com.paterva.maltego.transform.protocol.v2.RemoteTransformAdapterV2'


class VisibilityType(object):
    Public = 'public'
    Private = 'private'


class BuiltInTransformSets(object):
    ConvertToDomain = "Convert to Domain"
    DomainsUsingMXNS = "Domains using MX NS"
    FindOnWebpage = "Find on webpage"
    RelatedEmailAddresses = "Related Email addresses"
    DNSFromDomain = "DNS from Domain"
    EmailAddressesFromDomain = "Email addresses from Domain"
    IPOwnerDetail = "IP owner detail"
    ResolveToIP = "Resolve to IP"
    DNSFromIP = "DNS from IP"
    EmailAddressesFromPerson = "Email addresses from Person"
    InfoFromNS = "Info from NS"
    DomainFromDNS = "Domain From DNS"
    FilesAndDocumentsFromDomain = "Files and Documents from Domain"
    LinksInAndOutOfSite = "Links in and out of site"
    DomainOwnerDetail = "Domain owner detail"
    FilesAndDocumentsFromPhrase = "Files and Documents from Phrase"


class Set(MaltegoElement):
    name = fields_.String()


class Transform(MaltegoElement):
    name = fields_.String()


class TransformSet(MaltegoElement):

    name = fields_.String()
    description = fields_.String(default='')
    transforms = fields_.List(Transform, tagname='Transforms')

    def appendelement(self, other):
        if isinstance(other, Transform):
            self.transforms.append(other)

    def removeelement(self, other):
        if isinstance(other, Transform):
            self.transforms.remove(other)


class InputConstraint(MaltegoElement):

    class meta:
        tagname = 'Entity'

    type = fields_.String()
    min = fields_.Integer(default=1)
    max = fields_.Integer(default=1)


class OutputEntity(InputConstraint):

    class meta:
        tagname = 'Entity'


class InputEntity(InputConstraint):

    class meta:
        tagname = 'Entity'


class PropertyType(object):
    String = 'string'
    Boolean = 'boolean'
    Integer = 'int'


class TransformProperty(MaltegoElement):

    class meta:
        tagname = 'Property'

    defaultvalue = fields_.String(tagname='DefaultValue', required=False)
    samplevalue = fields_.String(tagname='SampleValue', default='')
    abstract = fields_.Boolean(default=False)
    description = fields_.String(default='')
    displayname = fields_.String(attrname='displayName')
    hidden = fields_.Boolean(default=False)
    name = fields_.String()
    nullable = fields_.Boolean(default=False)
    readonly = fields_.Boolean(default=False)
    popup = fields_.Boolean(default=False)
    type = fields_.String(default=PropertyType.String)
    visibility = fields_.String(default=VisibilityType.Public)


class TransformPropertySetting(MaltegoElement):

    class meta:
        tagname='Property'

    name = fields_.String()
    popup = fields_.Boolean(default=False)
    type = fields_.String(default=PropertyType.String)
    value = fields_.String(tagname=".")


def CmdLineTransformProperty(cmd=''):
    return TransformProperty(
        name='transform.local.command',
        defaultvalue=cmd,
        displayname='Command line',
        description='The command to execute for this transform'
    )


def CmdLineTransformPropertySetting(cmd=''):
    return TransformPropertySetting(
        name='transform.local.command',
        value=cmd
    )


def CmdParmTransformProperty(params=''):
    return TransformProperty(
        name='transform.local.parameters',
        defaultvalue=params,
        displayname='Command parameters',
        description='The parameters to pass to the transform command'
    )


def CmdParmTransformPropertySetting(params=''):
    return TransformPropertySetting(
        name='transform.local.parameters',
        value=params
    )


def CmdCwdTransformProperty(cwd=''):
    return TransformProperty(
        name='transform.local.working-directory',
        defaultvalue=cwd,
        displayname='Working directory',
        description='The working directory used when invoking the executable',
        samplevalue='/'
    )


def CmdCwdTransformPropertySetting(cwd=''):
    return TransformPropertySetting(
        name='transform.local.working-directory',
        value=cwd
    )


def CmdDbgTransformProperty(dbg=False):
    return TransformProperty(
        name='transform.local.debug',
        defaultvalue=str(dbg).lower(),
        displayname='Show debug info',
        description="When this is set, the transform's text output will be printed to the output window",
        samplevalue='false',
        type=PropertyType.Boolean
    )


def CmdDbgTransformPropertySetting(dbg=False):
    return TransformPropertySetting(
        name='transform.local.debug',
        value=str(dbg).lower(),
        type=PropertyType.Boolean
    )


class TransformSettings(MaltegoElement):

    enabled = fields_.Boolean(default=True)
    accepted = fields_.Boolean(default=False, attrname='disclaimerAccepted')
    showhelp = fields_.Boolean(default=True, attrname='showHelp')
    properties = fields_.List(TransformPropertySetting, tagname='Properties')

    def appendelement(self, other):
        if isinstance(other, TransformPropertySetting):
            self.properties.append(other)

    def removeelement(self, other):
        if isinstance(other, TransformPropertySetting):
            self.properties.remove(other)


class Protocol(MaltegoElement):

    version = fields_.String(default='2.0')


class AuthenticationType(object):
    Anonymous = 'none'
    Mac = 'mac'
    License = 'license'


class Authentication(MaltegoElement):

    type = fields_.String(default=AuthenticationType.Anonymous)


class MaltegoServer(MaltegoElement):

    name = fields_.String(default='Local')
    enabled = fields_.Boolean(default=True)
    description = fields_.String(default='Local transforms hosted on this machine')
    url = fields_.String(default='http://localhost')
    lastsync = fields_.String(tagname='LastSync', default=time.strftime('%Y-%m-%d'))
    protocol = fields_.Model(Protocol)
    authentication = fields_.Model(Authentication)
    transforms = fields_.List(Transform, tagname='Transforms')

    def appendelement(self, other):
        if isinstance(other, Transform):
            self.transforms.append(other)

    def removeelement(self, other):
        if isinstance(other, Transform):
            self.transforms.remove(other)


class EntityCategory(MaltegoElement):

    name = fields_.String()


class attr(MaltegoElement):
    name = fields_.String()
    stringvalue = fields_.String(required=False)
    boolvalue = fields_.Boolean(required=False)


class fileobject(MaltegoElement):

    name = fields_.String()
    attrs = fields_.Dict(attr, key='name')

    def appendelement(self, other):
        if isinstance(other, attr):
            self.attrs[other.name] = other

    def removeelement(self, other):
        if isinstance(other, attr):
            del self.attrs[other.name]


class attributes(MaltegoElement):

    version = fields_.String(default='1.0')
    fileobjects = fields_.Dict(fileobject, key='name')

    def appendelement(self, other):
        if isinstance(other, fileobject):
            self.fileobjects[other.name] = other

    def removeelement(self, other):
        if isinstance(other, fileobject):
            del self.fileobjects[other.name]


class Properties(MaltegoElement):

    fields = fields_.Dict(TransformProperty, key='name', tagname='Fields')

    def appendelement(self, other):
        if isinstance(other, TransformProperty):
            self.fields[other.name] = other

    def removeelement(self, other):
        if isinstance(other, TransformProperty):
            del self.fields[other.name]


class MaltegoTransform(MaltegoElement):

    name = fields_.String()
    displayname = fields_.String(attrname='displayName', default='')
    abstract = fields_.String(default=False)
    template = fields_.Boolean(default=False)
    visibility = fields_.String(default=VisibilityType.Public)
    description = fields_.String(default='')
    helpurl = fields_.String(attrname='helpURL', default='')
    author = fields_.String(default='')
    owner = fields_.String(default='')
    locrel = fields_.String(attrname='locationRelevance', default='global')
    version = fields_.String(default='1.0')
    requireinfo = fields_.Boolean(default=False, attrname='requireDisplayInfo')
    adapter = fields_.String(tagname='TransformAdapter', default=TransformAdapter.Local)
    properties = fields_.Model(Properties)
    input = fields_.List(InputConstraint, tagname='InputConstraints', required=False)
    output = fields_.List(OutputEntity, tagname='OutputEntities', required=False)
    help = fields_.CDATA(tagname='Help', default='')
    disclaimer = fields_.CDATA(tagname='Disclaimer', default='')
    sets = fields_.List(Set, tagname='defaultSets')
    stealthlevel = fields_.Integer(tagname='StealthLevel', default=0)
    authenticator = fields_.String(tagname='Authenticator', required=False)

    def appendelement(self, other):
        if isinstance(other, Set):
            self.sets.append(other)
        elif isinstance(other, TransformProperty):
            self.properties.fields_.append(other)
        elif isinstance(other, InputConstraint) or isinstance(other, InputEntity):
            self.input.append(other)
        elif isinstance(other, OutputEntity):
            self.output.append(other)

    def removeelement(self, other):
        if isinstance(other, Set):
            self.sets.remove(other)
        if isinstance(other, TransformProperty):
            self.properties.fields_.remove(other)
        elif isinstance(other, InputConstraint) or isinstance(other, InputEntity):
            self.input.remove(other)
        elif isinstance(other, OutputEntity):
            self.output.remove(other)


class Field(MaltegoElement):

    name = fields_.String()
    type = fields_.String()
    nullable = fields_.Boolean(default=True)
    hidden = fields_.Boolean(default=False)
    readonly = fields_.Boolean(default=False)
    description = fields_.String(required=False)
    displayname = fields_.String(attrname='displayName')
    defaultvalue = fields_.String(tagname='DefaultValue', required=False)
    samplevalue = fields_.String(tagname='SampleValue', default='')


class Groups(MaltegoElement):
    pass


class EntityProperties(MaltegoElement):

    class meta:
        tagname = 'Properties'

    value = fields_.String(required=False)
    groups = fields_.Model(Groups, required=False)
    fields = fields_.Dict(Field, key='name', tagname='Fields', required=False)


class RegexGroup(MaltegoElement):

    property = fields_.String(required=False)


class Converter(MaltegoElement):

    value = fields_.CDATA(default='', tagname='Value', required=False)
    regexgroups = fields_.Dict(RegexGroup, key='property', required=False)


class MaltegoEntity(MaltegoElement):

    id = fields_.String()
    displayname = fields_.String(attrname='displayName', required=False)
    plural = fields_.String(attrname='displayNamePlural', required=False)
    description = fields_.String(default='', required=False)
    category = fields_.String(required=False)
    smallicon = fields_.String(attrname='smallIconResource', required=False)
    largeicon = fields_.String(attrname='largeIconResource', required=False)
    allowedRoot = fields_.Boolean(default=True, required=False)
    conversion_order = fields_.Integer(attrname='conversionOrder', default=2147483647, required=False)
    visible = fields_.Boolean(default=True, required=False)
    largeicontag = fields_.String(tagname='Icon', required=False)
    smallicontag = fields_.String(tagname='SmallIcon', required=False)
    converter = fields_.Model(Converter, required=False)
    properties = fields_.Model(EntityProperties, required=False)
