'''
This state uses the manager webapp to manage Apache tomcat webapps
This state requires the manager webapp to be enabled

The following grains/pillar should be set::

    tomcat-manager.user: admin user name
    tomcat-manager.passwd: password

and also configure a user in the conf/tomcat-users.xml file::

    <?xml version='1.0' encoding='utf-8'?>
    <tomcat-users>
        <role rolename="manager-script"/>
        <user username="tomcat" password="tomcat" roles="manager-script"/>
    </tomcat-users>

Notes:

- Not supported multiple version on the same context path
- More information about tomcat manager: http://tomcat.apache.org/tomcat-7.0-doc/manager-howto.html
- if you use only this module for deployments you've might want to strict access to the manager only from localhost
  for more info: http://tomcat.apache.org/tomcat-7.0-doc/manager-howto.html#Configuring_Manager_Application_Access
- Tested on:

  JVM Vendor:
      Sun Microsystems Inc.
  JVM Version:
      1.6.0_43-b01
  OS Architecture:
      amd64
  OS Name:
      Linux
  OS Version:
      2.6.32-358.el6.x86_64
  Tomcat Version:
      Apache Tomcat/7.0.37
'''

# Private
def __virtual__():
    '''
    Load if the module tomcat exists
    '''

    return 'tomcat' if 'tomcat.status' in __salt__ else False

# Functions
def war_deployed(name, war, url='http://localhost:8080/manager', __env__='base', timeout=180):
    '''
    Enforce that the WAR will be deployed and started in the context path
    it will make use of WAR versions

    for more info: http://tomcat.apache.org/tomcat-7.0-doc/config/context.html#Naming

    name
        the context path to deploy
    war
        absolute path to WAR file (should be accessible by the user running
        tomcat) or a path supported by the salt.modules.cp.get_file function
    url : http://localhost:8080/manager
        the URL of the server manager webapp
    timeout : 180
        timeout for HTTP request to the tomcat manager

    Example::

        jenkins:
          tomcat.war_deployed:
            - name: /ran
            - war: salt://jenkins-1.2.4.war
            - require:
              - service: application-service
    '''

    # Prepare
    ret = {'name': name,
       'result': True,
       'changes': {},
       'comment': ''}
    basename = war.split('/')[-1]
    version = basename.replace('.war', '')
    webapps = __salt__['tomcat.ls'](url, timeout)
    deploy = False
    undeploy = False
    status = True

    # Determine what to do
    try:
        if version != webapps[name]['version']:
            deploy = True
            undeploy = True
            ret['changes']['undeploy'] = 'undeployed {0} in version {1}'.format(name, webapps[name]['version'])
            ret['changes']['deploy'] = 'will deploy {0} in version {1}'.format(name, version)
        else:
            deploy = False
            ret['comment'] = '{0} in version {1} is already deployed'.format(name, version)
            if webapps[name]['mode'] != 'running':
                ret['changes']['start'] = 'starting {0}'.format(name, version)
                status = False
    except Exception:
        deploy = True
        ret['changes']['deploy'] = 'deployed {0} in version {1}'.format(name, version)

    # Test
    if __opts__['test']:
        return ret

    # make sure the webapp is up if deployed
    if deploy == False:
        if status == False:
            ret['comment'] = __salt__['tomcat.start'](name, url, timeout=timeout)
            ret['result'] = ret['comment'].startswith('OK')
        return ret

    # Undeploy
    if undeploy:
        un = __salt__['tomcat.undeploy'](name, url, timeout=timeout)
        if un.startswith('FAIL'):
            ret['result'] = False
            ret['comment'] = un
            return ret

    # Deploy
    deploy_res = __salt__['tomcat.deploy_war'](war, name, 'yes', url, __env__, timeout)

    # Return
    if deploy_res.startswith('OK'):
        ret['result'] = True
        ret['comment'] = __salt__['tomcat.ls'](url, timeout)[name]
        ret['changes']['deploy'] = 'deployed {0} in version {1}'.format(name, version)
    else:
        ret['result'] = False
        ret['comment'] = deploy_res
        ret['changes'].pop('deploy')
    return ret

def wait(name, url='http://localhost:8080/manager', timeout=180):
    '''
    Wait for the tomcat manager to load

    notice that if the tomcat is not running we won't wait for it start and the state will fail
    this state can be required in the tomcat.war_deployed state to make sure tomcat is running and that the manager is running as well and ready for deployment

    url : http://localhost:8080/manager
        the URL of the server manager webapp
    timeout : 180
        timeout for HTTP request to the tomcat manager

    Example::

        tomcat-service:
          service:
            - running
            - name: tomcat
            - enable: True

        wait-for-tomcatmanager:
          tomcat:
            - wait
            - timeout: 300
            - require:
              - service: tomcat-service

        jenkins:
          tomcat:
            - war_deployed
            - name: /ran
            - war: salt://jenkins-1.2.4.war
            - require:
              - tomcat: wait-for-tomcatmanager
    '''

    result = __salt__['tomcat.status'](url, timeout)
    ret = {'name': name,
       'result': result,
       'changes': {},
       'comment': 'tomcat manager is ready' if result else 'tomcat manager is not ready'
       }

    return ret

def mod_watch(name, url='http://localhost:8080/manager', timeout=180):
    '''
    The tomcat watcher function.
    When called it will reload the webapp in question
    '''

    msg = __salt__['tomcat.reload'](name, url, timeout)
    result = msg.startswith('OK')

    ret = {'name': name,
       'result': result,
       'changes': {name: result},
       'comment': msg
       }

    return ret
