#- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# © Hub People 2024› https://www.hubpeople.be · https://www.geezteem.com/455
# AGPL-3.0-or-later - https://www.gnu.org/licenses/agpl-3.0.txt

#- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
import appy
from appy.px import Px
from appy.database import log
from appy.ui.sidebar import Sidebar
from appy.server.guard import Guard
from appy.model.workflow import Role
from appy.ui.template import Template
from appy.model.utils import Object as O
from appy.utils.ical import Config as IcalConfig
from appy.server import guard, scheduler, backup
from appy.server.context import AuthenticationContext
from appy import database, model, ui, server, deploy, peer

#- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
class AuthContext(AuthenticationContext):

    def getContexts(self, tool, user):
        '''HubPeople's authentication contexts are HP groups'''
        return [(str(group.iid), group.title) \
                for group in user.getHpGroups(sorted=True)]

    def isMandatory(self, tool, authenticate=False): return False

    def getDefaultContext(self, tool, user):
        '''If there is only one auth group, set it as default context'''
        contexts = self.getContexts(tool, user)
        if len(contexts) == 1: return contexts[0][0]

    def getObject(self, tool, user, context):
        '''Return the HsGroup corresponding the current authentication
           p_context.'''
        return tool.getObject(context) if context else None

#- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# Add custom CSS classes to main Appy classes
def getCssHP(part, px, context):
    '''Add specific HubPeople CSS classes to some p_parts within the
       standard Appy UI.'''
    if part == 'main':
        if px.name == 'home':
            r = 'homeHP'
        else:
            r = 'popupHP' if context.get('inPopup', False) else 'mainHP'
        return r

#- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
images = 'homeBG.jpg', 'loginLogo.png', 'homeLogo.png', 'headerBG.png', \
         'favicon.ico', 'inherited.png', 'unplanned.png', 'multiple.png', \
         'differs.png'

#- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
class Vars:
    '''Global variables'''

    # For a beneficiary living outside its group, what are the possibilities ?
    outsideTypes = ('auto', 'payback', 'noPayback', 'na')
    # "na" stands for "not applicable"

    # The existing HubPeople modules, with their acronym
    modules = {'journeyman': 'jm', 'timetracker': 'tt', 'medical': 'md'}

class Config(appy.Config):
    '''Main app configuration'''

    server   = server.Config()

    # Security
    security = guard.Config()
    security.authContext = AuthContext(chooseOnLogin=False)
    security.sessionTimeout = 180 # minutes (3 hours)

    backup = backup.Config()
    jobs = scheduler.Config()

    # Database
    database = database.Config()
    database.unlockers.append(Role('GroupAdmin', local=True))

    log = log.Config()
    deploy = deploy.Config()
    peers = peer.Config()

    # Model
    model = model.Config()
    model.rootClasses = ['Message', 'Beneficiary', 'Tag', 'Contact', 'HpGroup',
                         'Invoice']

    # User interface
    ui = ui.Config()
    ui.compact = True
    ui.languages = ('en', 'fr', 'de', 'nl')
    ui.sourceLanguage = ui.fallbackLanguage = 'fr'
    ui.languageSelector = True
    ui.selectableLanguages = ('fr', 'de') # Other languages are not complete
    ui.discreetLogin = False
    ui.fonts = "'Abel', sans-serif"
    ui.fontSize = '115%'
    ui.googleFonts = ('Abel',)
    ui.headerShow = lambda px, ctx: 'top' if not ctx.isAnon else None
    ui.topSpanWeight = 'normal'
    ui.headerSpanColor = ui.darkColor
    ui.selectColor = ui.darkColor
    ui.homeShowLogo = False
    ui.homeTextColor = 'black'
    ui.homeTextTop = '0'
    ui.wrongTextColor = '#f9f2f5'
    ui.showHomeIcon = False
    ui.showUserLink = False # Is placed in a custom PX elsewhere
    for name in images:
        ui.images[name] = 'HubPeople'
    ui.fieldBottom = '0.5em'

    # Styling the login box
    ui.darkColor = '#555555'
    ui.altColor = ui.lightColor = '#d0d0d0'
    ui.thColor = ui.thBdColor = '#555555'
    ui.thBgColor = '#d0d0d0'
    ui.altColorLight = '#ebe6ea'
    ui.linkColor = ui.visitedColor = '#a53f71'
    ui.loginBorder = '2px solid'
    ui.loginColorPh = ui.altColor
    ui.loginWeightPh = 'none'
    ui.loginBorderRadius = '15px'
    ui.loginRadius = '5px'
    ui.loginAlign = 'center'
    ui.loginBoxPadding = '30px 50px'
    ui.loginBgColor = ui.linkColor
    ui.submitBgRadius = '5px'
    ui.itextBottomColor = ui.linkColor

    # Styling the message box and Python interpreter
    ui.fillColor = ui.svg.fillColor = '#a98c9a'
    ui.pythonBgColor = '#a8a8a8'

    # Styling popups
    ui.popupColor = ui.darkColor

    # Styling buttons
    ui.buttonColor = ui.darkColor
    ui.buttonCase = 'none'

    # Styling the header
    ui.headerColor = ui.linkColor
    ui.headerHeight = '75px'
    ui.headerBgColor = ui.brightColor
    ui.burgerMargin = '0 1em'
    ui.topIconsMargin = '0 0.7em 0 0'

    # Styling the portlet
    ui.portletShowLogo = False
    ui.portletShowSeps = False
    ui.portletPadding = '30px 20px 0 0'
    ui.portletShadow = 'unset'
    ui.portletWidth = '261px'
    ui.portletMinWidth = '241px'
    ui.portletBgColor = '#a64172'
    ui.portletSep = 'none'
    ui.portletSepGap = '0.7em'
    ui.portletTextColor = ui.brightColor
    ui.portletHob = 'white'
    ui.portletHoc = ui.linkColor
    ui.pgMargin = '0 2px 0 0'
    ui.sdropMargin = '0.3em 0 0 0.2em'
    ui.lsInputBgColor = ui.brightColor
    ui.lsInputWidth = '6em'
    ui.lsInputHeight = '25px'
    ui.lsInputPadding = '0 5px'
    ui.lsrBgColor = '#d4bfd0'

    # Styling tabs and pictos (=pages)
    ui.tabMarginP = '0 0 20px 0'
    ui.tabColor = ui.linkColor
    ui.tabBorder = '1px solid %s' % ui.linkColor
    ui.tabBorderBottom = ui.tabBorderBottomP = ui.tabBorder
    ui.tabBorderRadius = '10px 10px 0 0'
    ui.pageGap = '0.6em 1em'
    ui.pageCHeight = 'auto'
    ui.pageCWidth = 'auto'
    ui.pageCPadding = '5px 15px'
    ui.pageDisplay = 'inline'
    ui.pageCRadius = '0 0 10px 10px'
    ui.navsPadding = '0 0 0 15px'
    ui.pictoCWidth = ui.pictoCHeight = '20px'
    ui.pictoCMargin = '0 5px 5px 0'
    ui.epictoPosition = 'inherit'
    ui.epictoPadding = '0 0 0 5px'
    ui.phaseBorderColor = 'transparent'
    ui.phaseBgColor = '#cab4c7'
    ui.phaseBgcColor = ui.altColor
    ui.phaseBorderColor = 'transparent'
    ui.phaseColor = ui.darkColor
    ui.phaseCcolor = ui.brightColor
    ui.pageCTextTransform = 'none'
    ui.pageCFontSize = '90%'

    # Styling PODs
    ui.podIRightC = '2px'

    # Styling searches
    ui.gridFiltersMargin = '5px 0 0 0'

    # Choosing background
    ui.baseBackground  = [None, 'no-repeat', 'cover']
    ui.css = getCssHP

    # Customize colors within SVG images
    ui.svg.mainColor = '#384554'
    ui.svg.flashyColor = ui.linkColor
    ui.svg.showyColor = '#555555'

    # Adding more ckeditor options
    ui.ckDistribution = 'full-all'

    # HubPeople-specific colors
    ui.lightBgColor = '#ede6ec'

    # The method for dumping message descriptions in ical events is custom
    ical = IcalConfig()
    ical.defaultValues['DESCRIPTION'] = ':o.icalDescription()'

    # Medical sidebar, shown on HpGroup and benData objects
    mediSidebar = Sidebar(width=444, maxWidth=600)

    # The maximum number of repetitions for a task or meet, depending on repeat
    # period.
    maxRepetitions = {'day': 50, 'week': 52, 'fortnight': 26, 'month': 24,
                      'other': 20, 'year': 5, 'custom': 40, None: 20}

    # When no end date is specified for a message, but we need one, we compute
    # an hypothetic end date by adding "deltaHour" to the message's start date.
    deltaHour = 1.0

    # The minimum and maximum number of hours for fields HpGroup.recentHours
    # (implicitly, in the future) and HpGroup.recentHoursPast.
    recentRanges = O(future=O(min=15, max=100), past=O(min=15, max=170))

    # The minimum and maximum meet durations (used for validating
    # HpGroup.defaultMeetDuration).
    meetDurationRange = O(min=5, max=1440) # Max = 24 hours

    # Removing a HP group completely, all sub-objects and messages included, is
    # so critical that it requires this file-system configuration option to be
    # activated in order to be available to an administrator via the UI.
    allowGroupDeletion = False

    # Default country and languages for contacts
    defaultCountry = 'BE'
    defaultLanguage = defaultCountryLanguage = 'fr'

    # Default duration for end meets (in minutes)
    endMeetDuration = 30

#- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
try: # to import the site-specific configuration file
    import config
    config.complete(Config)
except ImportError:
    # The "config" module may not be present at maketime
    pass

#- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# Login box: add the links to other workspaces
Guard.pxLoginBottom = Px('''
 <p class="loginLinks">
  Workspaces ·
  <x for="i in range(10)">
   <a href=":'https://workspace%s.plat-com.org' % (i or '')">:i</a> ·</x>
  <a href="https://aviq.plat-com.org"> AViQ</a> ·
  <a href="https://sante.plat-com.org"> Santé</a>
 </p>''',

 css='''
   .loginLinks { font-size:90%}
   .loginLinks a, .loginLinks a:visited {
     color:|loginBgColor|; font-weight:bold}''')

#- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# Add "welcome user" in the left
Template.pxLinksBefore = Px('''
 <span class="burgerSpan" if="not isAnon"><x>:_('app_welcome')</x>
  <a href=":user.url"><x>:user.firstName or user.login</x>
   <img src=":svg('user')"/></a>
 </span>''',

 css='''.burgerSpan { text-transform: uppercase; padding-left:20px;
                      font-size:130%; letter-spacing:1px; color:black }
        .burgerSpan a { padding-left:0.5em }
        .burgerSpan img { padding-left:1em; width:27px }''')

# Add the icon at the center of the header
Template.pxLinks = Px('''
 <div class="bannerPellet" if="not isAnon">
  <a href="/"><img src=":url('pellet', base='HubPeople')"/></a>
 </div>''')

# Add specific icons and links
Template.pxLinksAfter = Px('''
 <!-- Links to pages on hubpeople.be -->
 <x if="isAnon">
  <a href="https://www.hubpeople.be/cgu">:_('terms_of_use')</a>
  <a href="https://tubedu.org/a/hubpeople_tutos/video-channels">·
   <x>:_('tutorials')</x> ·</a>
  <a href="https://www.hubpeople.be/versions">Plat-com v2.1.1 ⛺
   18/03/2026</a>
 </x>
 <x var="group=tool.getAuthGroup()">

  <!-- Go to the auth group -->
  <a if="group and not user.isFaceted()" href=":group.url"
     title=":_('goto_group')">
   <img src=":svg('groups')" class="iconL"/></a>

  <!-- Refresh meet and task statuses -->
  <a if="group and user.isManagerOn(group)"
     href=":f'{tool.url}/onRefreshStatuses'" onclick="setRotate(this)">
   <img title=":_('refresh_statuses')" src=":svg('refresh')" class="iconL"/>
  </a>

  <!-- Go to the medical planning -->
  <a if="group and user.caresOn(group)"
     href=":f'{group.url}/view?page=mediPlanning'">
   <img title=":_('medical_access')" src=":svg('medical')" class="iconL"/>
  </a>

  <!-- The timetracker button for a timetracked user -->
  <x var="icon=user.getTimespanIcon()" if="icon">::icon</x>
 </x>''',

 js='''function setRotate(a){
     a.className = 'unclickable';
     a.firstChild.className = a.firstChild.className + ' waitRotate';
     setMask();
   }''',

 css='''
  @keyframes wRotate {50% {transform:rotate(180deg)}}
  .waitRotate { animation:wRotate 1s infinite }''')
#- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
