# -*- coding: utf-8 -*-

"""
    Request Management
"""

module = request.controller
resourcename = request.function

if not settings.has_module(module):
    raise HTTP(404, body="Module disabled: %s" % module)

# -----------------------------------------------------------------------------
def index():
    """ Module's Home Page """

    return s3db.cms_index(module, alt_function="index_alt")

# -----------------------------------------------------------------------------
def index_alt():
    """
        Module homepage for non-Admin users when no CMS content found
    """

    # Just redirect to the list of Requests
    redirect(URL(f="req"))

# -----------------------------------------------------------------------------
def is_affiliated():
    """
        Check if User is affiliated to an Organisation
        @ToDo: Move this elsewhere
    """

    if not auth.is_logged_in():
        return False
    elif s3_has_role(ADMIN):
        return True
    else:
        table = auth.settings.table_user
        auth_user = db(table.id == auth.user.id).select(table.organisation_id,
                                                        limitby=(0, 1)
                                                        ).first()
        if auth_user and auth_user.organisation_id:
            return True
        else:
            return False

# =============================================================================
def create():
    """ Redirect to req/create """

    redirect(URL(f="req", args="create"))

# -----------------------------------------------------------------------------
def marker_fn(record):
    """
        Function to decide which Marker to use for Requests Map
    """

    # Base Icon based on Type
    type = record.type
    if type in (1, 8):
        # Items
        marker = "asset"
    elif type == 3:
        # People
        marker = "staff"
    #elif type == 6:
    #    # Food
    #    marker = "food"
    else:
        marker = "request"

    # Colour code by priority
    priority = record.priority
    if priority == 3:
        # High
        marker = "%s_red" % marker
    elif priority == 2:
        # Medium
        marker = "%s_yellow" % marker
    #elif priority == 1:
    #    # Low
    #    marker = "%s_yellow" % marker

    mtable = db.gis_marker
    marker = db(mtable.name == marker).select(mtable.image,
                                              mtable.height,
                                              mtable.width,
                                              cache=s3db.cache,
                                              limitby=(0, 1)).first()
    return marker

# -----------------------------------------------------------------------------
def req():
    """
        REST Controller for Request Instances
    """

    s3.filter = (s3db.req_req.is_template == False)

    output = req_controller()
    return output

# -----------------------------------------------------------------------------
def req_template():
    """
        REST Controller for Request Templates
    """

    # Hide fields which aren't relevant to templates
    # @ToDo: Need to get this done later after being opened by Types?
    table = s3db.req_req
    field = table.is_template
    field.default = True
    field.readable = field.writable = False
    s3.filter = (field == True)

    settings.req.prompt_match = False

    if "req_item" in request.args:
        # List fields for req_item
        table = s3db.req_req_item
        list_fields = ["id",
                       "item_id",
                       "item_pack_id",
                       "quantity",
                       "comments",
                       ]
        s3db.configure("req_req_item",
                       list_fields = list_fields,
                       )

    elif "req_skill" in request.args:
        # List fields for req_skill
        table = s3db.req_req_skill
        list_fields = ["id",
                       "skill_id",
                       "quantity",
                       "comments",
                       ]
        s3db.configure("req_req_skill",
                       list_fields = list_fields,
                       )

    else:
        # Main Req
        fields = ["req_ref",
                  "date",
                  "date_required",
                  "date_required_until",
                  "date_recv",
                  "recv_by_id",
                  "cancel",
                  "commit_status",
                  "transit_status",
                  "fulfil_status",
                  ]
        for fieldname in fields:
            field = table[fieldname]
            field.readable = field.writable = False
        table.purpose.label = T("Details")
        list_fields = ["id",
                       "site_id"
                       ]
        if len(settings.get_req_req_type()) > 1:
            list_fields.append("type")
        list_fields.append("priority")
        list_fields.append("purpose")
        list_fields.append("comments")
        s3db.configure("req_req",
                       list_fields = list_fields,
                       )

        # CRUD strings
        s3.crud_strings["req_req"] = Storage(
            label_create = T("Create Request Template"),
            title_display = T("Request Template Details"),
            title_list = T("Request Templates"),
            title_update = T("Edit Request Template"),
            label_list_button = T("List Request Templates"),
            label_delete_button = T("Delete Request Template"),
            msg_record_created = T("Request Template Added"),
            msg_record_modified = T("Request Template Updated"),
            msg_record_deleted = T("Request Template Deleted"),
            msg_list_empty = T("No Request Templates"))

    output = req_controller(template = True)
    return output

# -----------------------------------------------------------------------------
def req_controller(template = False):
    """ REST Controller """

    def prep(r):

        table = r.table
        s3.req_prep(r)

        #if len(settings.get_req_req_type()) == 1:
        #    # Remove type from list_fields
        #    list_fields = s3db.get_config("req_req", "list_fields")
        #    try:
        #        list_fields.remove("type")
        #    except:
        #         # It has already been removed.
        #         # This can happen if the req controller is called
        #         # for a second time, such as when printing reports
        #        pass
        #    s3db.configure("req_req", list_fields=list_fields)

        type = (r.record and r.record.type) or \
               (request.vars.type and int(request.vars.type))

        if r.interactive:
            # Set the req_item site_id (Requested From), called from action buttons on req/req_item_inv_item/x page
            if "req_item_id" in request.vars and "inv_item_id" in request.vars:
                iitable = s3db.inv_inv_item
                inv_item = db(iitable.id == request.vars.inv_item_id).select(iitable.site_id,
                                                                             iitable.item_id,
                                                                             limitby=(0, 1)
                                                                             ).first()
                site_id = inv_item.site_id
                item_id = inv_item.item_id
                # @ToDo: Check Permissions & Avoid DB updates in GETs
                db(s3db.req_req_item.id == request.vars.req_item_id).update(site_id = site_id)
                response.confirmation = T("%(item)s requested from %(site)s") % \
                    {"item": s3db.supply_ItemRepresent()(item_id),
                     "site": s3db.org_SiteRepresent()(site_id)
                     }
            elif "req.site_id" in r.get_vars:
                # Called from 'Make new request' button on [siteinstance]/req page
                table.site_id.default = get_vars.get("req.site_id")
                table.site_id.writable = False
                if r.http == "POST":
                    del r.get_vars["req.site_id"]

            table.requester_id.represent = requester_represent

            # Set Fields and Labels depending on type
            if type:
                table.type.default = type

                # This prevents the type from being edited AFTER it is set
                table.type.readable = table.type.writable = False

                crud_strings = settings.get_req_req_crud_strings(type)
                if crud_strings:
                    s3.crud_strings["req_req"] = crud_strings
                elif type == 1:
                    s3.crud_strings["req_req"].label_create = T("Make Supplies Request")
                elif type == 3:
                    s3.crud_strings["req_req"].label_create = T("Make People Request")

                # Filter the query based on type
                if s3.filter:
                    s3.filter = s3.filter & \
                                (table.type == type)
                else:
                    s3.filter = (table.type == type)

            # These changes are applied via JS in create forms where type is editable
            if type == 1: # Item
                table.date_recv.readable = table.date_recv.writable = True

                if settings.get_req_items_ask_purpose():
                    table.purpose.label = T("What the Items will be used for")
                table.site_id.label = T("Deliver To")
                table.request_for_id.label = T("Deliver To")
                table.requester_id.label = T("Site Contact")
                table.recv_by_id.label = T("Delivered To")

            elif type == 3: # Person
                table.date_required_until.readable = table.date_required_until.writable = True

                table.purpose.label = T("Task Details")
                table.purpose.comment = DIV(_class="tooltip",
                                            _title="%s|%s" % (T("Task Details"),
                                                              T("Include any special requirements such as equipment which they need to bring.")))
                table.site_id.label =  T("Report To")
                table.requester_id.label = T("Volunteer Contact")
                table.request_for_id.label = T("Report To")
                table.recv_by_id.label = T("Reported To")

            if r.component:
                if r.component.name == "document":
                    s3.crud.submit_button = T("Add")
                    #table = r.component.table
                    # @ToDo: Fix for Link Table
                    #table.date.default = r.record.date
                    #if r.record.site_id:
                    #    stable = db.org_site
                    #    query = (stable.id == r.record.site_id)
                    #    site = db(query).select(stable.location_id,
                    #                            stable.organisation_id,
                    #                            limitby=(0, 1)).first()
                    #    if site:
                    #        table.location_id.default = site.location_id
                    #        table.organisation_id.default = site.organisation_id

                elif r.component.name == "req_item":
                    ctable = r.component.table
                    ctable.site_id.writable = ctable.site_id.readable = False
                    s3.req_hide_quantities(ctable)

                elif r.component.name == "req_skill":
                    s3.req_hide_quantities(r.component.table)

                elif r.component.alias == "job":
                    s3task.configure_tasktable_crud(
                        function="req_add_from_template",
                        args = [r.id],
                        vars = dict(user_id = auth.user is not None and auth.user.id or 0),
                        period = 86400, # seconds, so 1 day
                        )
                    db.scheduler_task.timeout.writable = False
            else:
                if r.id:
                    table.is_template.readable = table.is_template.writable = False

                method = r.method
                if method not in ("map", "read", "search", "update"):
                    # Hide fields which don't make sense in a Create form
                    # - includes one embedded in list_create
                    # - list_fields over-rides, so still visible within list itself
                    s3.req_create_form_mods()

                    if type and settings.get_req_inline_forms():
                        # Inline Forms
                        s3.req_inline_form(type, method)

                    # Get the default Facility for this user
                    #if settings.has_module("hrm"):
                    #    hrtable = s3db.hrm_human_resource
                    #    query = (hrtable.person_id == s3_logged_in_person())
                    #    site = db(query).select(hrtable.site_id,
                    #                            limitby=(0, 1)).first()
                    #    if site:
                    #        r.table.site_id.default = site.site_id
                    # Use site_id in User Profile
                    if auth.is_logged_in():
                        if not table.site_id.default:
                            table.site_id.default = auth.user.site_id

                elif method == "map":
                    # Tell the client to request per-feature markers
                    s3db.configure("req_req", marker_fn=marker_fn)

                elif method == "update":
                    if settings.get_req_inline_forms():
                        # Inline Forms
                        s3.req_inline_form(type, method)
                    s3.scripts.append("/%s/static/scripts/S3/s3.req_update.js" % appname)

            # Prevent Items from being added to closed or cancelled requests
            if r.record and (r.record.closed or r.record.cancel):
                s3db.configure("req_req_item",
                               insertable = False)

        elif r.representation == "plain":
            # Map Popups
            pass

        elif r.representation == "geojson":
            req_ref_represent = table.req_ref.represent
            table.req_ref.represent = lambda v, show_link=False, pdf=False: \
                req_ref_represent(v, show_link)
            # Load these models now as they'll be needed when we encode
            mtable = s3db.gis_marker
            s3db.configure("req_req", marker_fn=marker_fn)

        if r.component and r.component.name == "commit":
            table = r.component.table
            record = r.record
            stable = s3db.org_site
            commit_status = record.commit_status

            # Commits belonging to this request
            rsites = []
            query = (table.deleted == False)&(table.req_id == record.id)
            req_sites = db(query).select(table.site_id)
            for req_site in req_sites:
                rsites += [req_site.site_id]

            # All the sites
            commit_sites = db((stable.deleted == False)).select(stable.id,
                                                              stable.code)

            # Sites which have not committed to this request yet
            site_opts = {}
            for site in commit_sites:
                if (site.id not in site_opts) and (site.id not in rsites):
                    site_opts[site.id] = site.code

            table.site_id.requires = IS_IN_SET(site_opts)
            if (commit_status == 2) and settings.get_req_restrict_on_complete():
                # Restrict from committing to completed requests                
                listadd = False
            else:    
                # Allow commitments to be added when doing so as a component
                listadd = True

            s3db.configure(table,
                           # Don't want filter_widgets in the component view
                           filter_widgets = None,
                           listadd = listadd,
                           )

            if type == 1: # Items
                # Limit site_id to facilities the user has permissions for
                auth.permitted_facilities(table=r.table,
                                          error_msg=T("You do not have permission for any facility to make a commitment."))
                if r.interactive:
                    # Dropdown not Autocomplete
                    itable = s3db.req_commit_item
                    itable.req_item_id.widget = None
                    req_id = r.id
                    s3db.req_commit_item.req_item_id.requires = \
                                    IS_ONE_OF(db,
                                              "req_req_item.id",
                                              s3db.req_item_represent,
                                              orderby = "req_req_item.id",
                                              filterby = "req_id",
                                              filter_opts = [req_id],
                                              sort=True
                                              )
                    s3.jquery_ready.append('''
$.filterOptionsS3({
 'trigger':{'alias':'commit_item','name':'req_item_id'},
 'target':{'alias':'commit_item','name':'item_pack_id'},
 'scope':'row',
 'lookupPrefix':'req',
 'lookupResource':'req_item_packs',
 'lookupKey':'req_item_id',
 'lookupField':'id',
 'msgNoRecords':i18n.no_packs,
 'fncPrep':S3.supply.fncPrepItem,
 'fncRepresent':S3.supply.fncRepresentItem
})''')
                    # Custom Form
                    s3forms = s3base.s3forms
                    crud_form = s3forms.S3SQLCustomForm(
                            "site_id",
                            "date",
                            "date_available",
                            "committer_id",
                            s3forms.S3SQLInlineComponent(
                                "commit_item",
                                label = T("Items"),
                                fields = ["req_item_id",
                                          "item_pack_id",
                                          "quantity",
                                          "comments"
                                          ]
                            ),
                            "comments",
                        )
                    s3db.configure("req_commit",
                                   crud_form = crud_form)
                    # Redirect to the Items tab after creation
                    #s3db.configure(table,
                    #               create_next = URL(c="req", f="commit",
                    #                                 args=["[id]", "commit_item"]),
                    #               update_next = URL(c="req", f="commit",
                    #                                 args=["[id]", "commit_item"]))

            elif type == 3: # People
                # Limit site_id to orgs the user has permissions for
                # @ToDo: Make this customisable between Site/Org
                # @ToDo: is_affiliated()
                auth.permitted_facilities(table=r.table,
                                          error_msg=T("You do not have permission for any facility to make a commitment."))
                # Limit organisation_id to organisations the user has permissions for
                #auth.permitted_organisations(table=r.table, redirect_on_error=False)
                if r.interactive:
                    #table.organisation_id.readable = True
                    #table.organisation_id.writable = True
                    # Custom Form
                    s3forms = s3base.s3forms
                    crud_form = s3forms.S3SQLCustomForm(
                            "site_id",
                            "date",
                            "date_available",
                            "committer_id",
                            s3forms.S3SQLInlineComponent(
                                "commit_skill",
                                label = T("Skills"),
                                fields = ["quantity",
                                          "skill_id",
                                          "comments"
                                          ]
                            ),
                            "comments",
                        )
                    s3db.configure("req_commit",
                                   crud_form = crud_form)
                    # Redirect to the Skills tab after creation
                    #s3db.configure(table,
                    #               create_next = URL(c="req", f="commit",
                    #                                 args=["[id]", "commit_skill"]),
                    #               update_next = URL(c="req", f="commit",
                    #                                 args=["[id]", "commit_skill"]))
            else:
                # Non-Item commits can have an Organisation
                # Check if user is affiliated to an Organisation
                if is_affiliated():
                    # Limit organisation_id to organisations the user has permissions for
                    auth.permitted_organisations(table=r.table,
                                                 redirect_on_error=False)
                    table.organisation_id.readable = table.organisation_id.writable = True
                else:
                    # Unaffiliated people can't commit on behalf of others
                    field = r.component.table.committer_id
                    field.writable = False
                    field.comment = None

                # Non-Item commits shouldn't have a From Inventory
                # @ToDo: Assets do? (Well, a 'From Site')
                table.site_id.readable = table.site_id.writable = False
                #if r.interactive and r.record.type == 3: # People
                #    # Redirect to the Persons tab after creation
                #    s3db.configure(table,
                #                   create_next = URL(c="req", f="commit",
                #                                     args=["[id]", "commit_person"]),
                #                   update_next = URL(c="req", f="commit",
                #                                     args=["[id]", "commit_person"])
                #                   )
        else:
            # Limit site_id to facilities the user has permissions for
            # @ToDo: Non-Item requests shouldn't be bound to a Facility?
            auth.permitted_facilities(table=r.table,
                                      error_msg=T("You do not have permission for any facility to make a request."))
        return True
    s3.prep = prep

    # Post-process
    def postp(r, output):

        if r.interactive and r.method != "import":
            if not r.component:
                s3_action_buttons(r)
                #s3_action_buttons(r, copyable=True)
                # if "buttons" in output:
                    # buttons = output["buttons"]
                    # if "delete_btn" in buttons:
                        # delete_btn = buttons["delete_btn"]
                        # delete_btn = DIV(delete_btn,
                                         # A(T("Copy Request"),
                                           # _href=URL(args=[r.id, "copy"],
                                                     ##vars={"type":r.record.type}
                                                     # ),
                                           # _class="action-btn"))
                        # output["buttons"]["delete_btn"] = delete_btn
                if not template and settings.get_req_use_commit():
                    # This is appropriate to all
                    s3.actions.append(
                        dict(url = URL(c="req", f="req",
                                       args=["[id]", "commit_all"]),
                             _class = "action-btn commit-btn",
                             label = str(T("Commit"))
                            )
                        )
                    s3.jquery_ready.append(
'''S3.confirmClick('.commit-btn','%s')''' % T("Do you want to commit to this request?"))
                # This is only appropriate for item requests
                #query = (r.table.type == 1)
                #rows = db(query).select(r.table.id)
                #restrict = [str(row.id) for row in rows]
                #s3.actions.append(
                #    dict(url = URL(c="req", f="req",
                #                   args=["[id]", "req_item"]),
                #         _class = "action-btn",
                #         label = str(T("View Items")),
                #         restrict = restrict
                #        )
                #    )
                # This is only appropriate for people requests
                #query = (r.table.type == 3)
                #rows = db(query).select(r.table.id)
                #restrict = [str(row.id) for row in rows]
                #s3.actions.append(
                #    dict(url = URL(c="req", f="req",
                #                   args=["[id]", "req_skill"]),
                #         _class = "action-btn",
                #         label = str(T("View Skills")),
                #         restrict = restrict
                #        )
                #    )
                s3.actions.append(
                        dict(url = URL(c="req", f="req",
                                       args=["[id]", "copy_all"]),
                             _class = "action-btn send-btn copy_all",
                             label = str(T("Copy"))
                            )
                        )
                if not template:
                    s3.actions.append(
                            dict(url = URL(c="req", f="req",
                                           args=["[id]", "commit_all", "send"]),
                                 _class = "action-btn send-btn dispatch",
                                 label = str(T("Send"))
                                )
                            )
                    s3.jquery_ready.append(
'''S3.confirmClick('.send-btn','%s')''' % T("Are you sure you want to commit to this request and send a shipment?"))
            else:
                s3_action_buttons(r)
                if r.component.name == "req_item" and settings.get_req_prompt_match():
                    req_item_inv_item_btn = dict(url = URL(c = "req",
                                                           f = "req_item_inv_item",
                                                           args = ["[id]"]
                                                          ),
                                                 _class = "action-btn",
                                                 label = str(T("Request from Facility")),
                                                 )
                    s3.actions.append(req_item_inv_item_btn)
                if r.component.name == "commit":
                    if "form" in output:
                        id = r.record.id
                        ctable = s3db.req_commit
                        query = (ctable.deleted == False) & \
                                (ctable.req_id == id)
                        exists = current.db(query).select(ctable.id, limitby=(0, 1))
                        if not exists:
                            s3.rfooter = A(T("Commit All"),
                                           _href=URL(args=[id, "commit_all"]),
                                           _class="action-btn",
                                           _id="commit-btn",
                                           )
                            s3.jquery_ready.append('''
S3.confirmClick('#commit-btn','%s')''' % T("Do you want to commit to this request?"))
                        else:
                            s3.actions.append(
                                          dict(url = URL(c="req", f="send_commit",
                                                         args = ["[id]"]),
                                               _class = "action-btn send-btn",
                                               label = str(T("Prepare Shipment"))
                                              )
                                       )
                            s3.jquery_ready.append(
'''S3.confirmClick('.send-btn','%s')''' % T("Are you sure you want to send this shipment?"))
                if r.component.alias == "job":
                    s3.actions = [
                        dict(label=str(T("Open")),
                             _class="action-btn",