/**
 *  Copyright (c) 2017 CentraleSupélec & EDF.
 *  All rights reserved. This program and the accompanying materials
 *  are made available under the terms of the Eclipse Public License v1.0
 *  which accompanies this distribution, and is available at
 *  http://www.eclipse.org/legal/epl-v10.html
 *
 *  This file is part of the RiseClipse tool
 * 
 *  Contributors:
 *      Computer Science Department, CentraleSupélec
 *      EDF R&D
 *  Contacts:
 *      dominique.marcadet@centralesupelec.fr
 *      aurelie.dehouck-neveu@edf.fr
 *  Web site:
 *      http://wdi.supelec.fr/software/RiseClipse/
 */

import scl: 'http://www.iec.ch/61850/2003/SCL'

package scl

context Val

    inv Val_enum_value_valid
    ( 'Value of Val is invalid according to Enum (line ' + self.lineNumber.toString() + ')' )
    :
        if( self.ParentDAI = null ) then
            true
        else if( self.ParentDAI.ParentDOI = null ) then
            true
        else
            let do : DO = self.ParentDAI.ParentDOI.ParentAnyLN.RefersToLNodeType.DO->select( do : DO | do.name = self.ParentDAI.ParentDOI.name )->any( true ) in
            let da : DA = do.RefersToDOType.DA->select( da : DA | da.name = self.ParentDAI.name )->any( true ) in
            if( da.RefersToEnumType <> null ) then
                da.RefersToEnumType.EnumVal.value->includes( self.value )
            else
                true
            endif
        endif endif
       
       inv Val_consistency
    ( 'Val in DAI must abide to DA.bType (line ' + self.lineNumber.toString() + ')' )
    :
    if self.value <> null then   
              if self.ParentDAI = null then
                    true
              else if self.ParentDAI.ParentDOI = null then
                     true
              else
                  let do : DO = self.ParentDAI.ParentDOI.ParentAnyLN.RefersToLNodeType.DO->select( do : DO | do.name = self.ParentDAI.ParentDOI.name )->any( true ) in
            let da : DA = do.RefersToDOType.DA->select( da : DA | da.name = self.ParentDAI.name )->any( true ) in
            (da.bType = 'BOOLEAN' implies
             self.value = '0' or self.value = '1'or self.value = 'true' or self.value = 'false')
            and
            (da.bType = 'INT8' implies
             if self.value.matches('[\u002D]{0,1}[0-9]+') then
             self.value.toInteger() >= -128 and self.value.toInteger() <= 127 else false endif)
            and
            (da.bType = 'INT16' implies
             if self.value.matches('[\u002D]{0,1}[0-9]+') then
             self.value.toInteger() >= -32768 and self.value.toInteger() <= 32767 else false endif)   
            and
            (da.bType = 'INT32' implies
             if self.value.matches('[\u002D]{0,1}[0-9]+') then
             self.value.toInteger() >= -2147483648 and self.value.toInteger() <= 2147483647 else false endif)
            and
            (da.bType = 'INT64' implies
             if self.value.matches('[\u002D]{0,1}[0-9]+') then
             self.value.toInteger() >= -9223372036854775808 and self.value.toInteger() <= 9223372036854775807 else false endif)
            and
            (da.bType = 'INT8U' implies
             if self.value.matches('[0-9]+') then
             self.value.toInteger() >= 0 and self.value.toInteger() <= 255 else false endif)                    
            and
            (da.bType = 'INT16U' implies
             if self.value.matches('[0-9]+') then
             self.value.toInteger() >= 0 and self.value.toInteger() <= 65535 else false endif)   
            and
            (da.bType = 'INT24U' implies
             if self.value.matches('[0-9]+') then
             self.value.toInteger() >= 0 and self.value.toInteger() <= 16777215 else false endif)   
            and
            (da.bType = 'INT32U' implies
             if self.value.matches('[0-9]+') then
             self.value.toInteger() >= 0 and self.value.toInteger() <= 4294967295 else false endif)
            and
            (da.bType = 'FLOAT32' implies --IEEE 754
             if (self.value.matches('[\u002D]{0,1}[0-9]{1,}[.]{0,1}[0-9]{0,}[e]{0,1}[\u002D]{0,1}[0-9]{0,}') and
                    (self.value.endsWith('e') implies false)) then
             self.value.toReal() >= '-3.40282346e38'.toReal() and self.value.toReal() <= '3.40282346e38'.toReal() else false endif) 
            and
            (da.bType = 'FLOAT64' implies --IEEE 754
             if (self.value.matches('[\u002D]{0,1}[0-9]{1,}[.]{0,1}[0-9]{0,}[e]{0,1}[\u002D]{0,1}[0-9]{0,}') and
                    (self.value.endsWith('e') implies false)) then
             self.value.toReal() >= '-1.7976931348623157e308'.toReal() and self.value.toReal() <= '1.7976931348623157e308'.toReal() else false endif)
            and
            (da.bType = 'Enum' implies
             da.RefersToEnumType <> null)
            and
            (da.bType = 'Timestamp' implies
             self.value.matches('[0-9A-Za-z:.-]*'))              
            and
            (da.bType = 'VisString32' implies --ISO/IEC 8859-1
             (self.value.matches('[\u0020-\u00FF ]*') and self.value.size() <= 32))
            and
            (da.bType = 'VisString64' implies --ISO/IEC 8859-1
             (self.value.matches('[\u0020-\u00FF ]*') and self.value.size() <= 64))
            and
            (da.bType = 'VisString65' implies --ISO/IEC 8859-1
             (self.value.matches('[\u0020-\u00FF ]*') and self.value.size() <= 65))
            and
            (da.bType = 'VisString129' implies --ISO/IEC 8859-1
             (self.value.matches('[\u0020-\u00FF ]*') and self.value.size() <= 129))
            and
            (da.bType = 'VisString255' implies --ISO/IEC 8859-1
             (self.value.matches('[\u0020-\u00FF ]*') and self.value.size() <= 255))
            and
            (da.bType = 'Unicode255' implies
             (self.value.matches('[\u0000-\uFFFF ]*') and self.value.size() <= 255))
            and
            (da.bType = 'ObjRef' implies -- IEC 61850-7-2
             ((self.value.matches('[\u0020-\u00FF ]{0,64}[/]{1}[\u0020-\u00FF ]{0,64}')
                    or self.value.matches('')
             )
                    and self.value.size() <= 129
             ))           
            and
            (da.bType = 'Currency' implies --ISO 4217
         (Set{'AED','AFN','ALL','AMD','ANG','AOA','ARS','AUD','AWG','AZN','BAM','BBD','BDT'
         ,'BGN','BHD','BIF','BMD','BND','BOB','BOV','BRL','BSD','BTN','BWP','BYN','BZD'
         ,'CAD','CDF','CHE','CHF','CHW','CLF','CLP','CNY','COP','COU','CRC','CUC','CUP'
         ,'CVE','CZK','DJF','DKK','DOP','DZD','EGP','ERN','ETB','EUR','FJD','FKP','GBP'
         ,'GEL','GHS','GIP','GMD','GNF','GTQ','GYD','HKD','HNL','HRK','HTG','HUF','IDR'
         ,'ILS','INR','IQD','IRR','ISK','JMD','JOD','JPY','KES','KGS','KHR','KMF','KPW'
         ,'KRW','KWD','KYD','KZT','LAK','LBP','LKR','LRD','LSL','LYD','MAD','MDL','MGA'
         ,'MKD','MMK','MNT','MOP','MRU','MUR','MVR','MWK','MXN','MXV','MYR','MZN','NAD'
         ,'NGN','NIO','NOK','NPR','NZD','OMR','PAB','PEN','PGK','PHP','PKR','PLN','PYG'
         ,'QAR','RON','RSD','RUB','RWF','SAR','SBD','SCR','SDG','SEK','SGD','SHP','SLL'
         ,'SOS','SRD','SSP','STN','SVC','SYP','SZL','THB','TJS','TMT','TND','TOP','TRY'
         ,'TTD','TWD','TZS','UAH','UGX','USD','USN','UYI','UYU','UZS','VEF','VND','VUV'
         ,'WST','XAF','XAG','XAU','XBA','XBB','XBC','XBD','XCD','XDR','XOF','XPD','XPF'
                    ,'XPT','XSU','XTS','XUA','XXX','YER','ZAR','ZMW','ZWL'} ->
              includes(self.value)))
            and
            (da.bType = 'Octet6' implies -- RFC 2045 (base64), for 61850-8-1 Edition 2.1
                    (self.value.matches( '[0-9A-Za-z/+]*' ) and self.value.size() <= 6))   
            and
            (da.bType = 'Octet16' implies -- RFC 2045 (base64), for 61850-8-1 Edition 2.1
                    (self.value.matches( '[0-9A-Za-z/+]*' ) and self.value.size() <= 16))   
            and
            (da.bType = 'Octet64' implies -- RFC 2045 (base64)
                    (self.value.matches( '[0-9A-Za-z/+]*' ) and self.value.size() <= 64))                         
                                                    
        endif
        endif
        else true endif

endpackage