local j={}local c=require(script.Parent.Logger)local L=require(script.Parent.Utilities)function j.validateCustomDimensions(L,c)return j:validateArrayOfStrings(20,32,false,"\099\117\115\116\111\109 \100\105\109\101\110\115\105\111\110\115",c)end function j.validateDimension(b,j,c)if L:isStringNullOrEmpty(c)then return true end if not L:stringArrayContainsString(j,c)then return false end return true end function j.validateResourceCurrencies(b,L)if not j:validateArrayOfStrings(20,64,false,"\114\101\115\111\117\114\099\101 \099\117\114\114\101\110\099\105\101\115",L)then return false end for j,L in pairs(L)do if not string.find(L,"\094\091\065-\090\097-\122\093\043\036")then c:w("\114\101\115\111\117\114\099\101 \099\117\114\114\101\110\099\105\101\115 \118\097\108\105\100\097\116\105\111\110 \102\097\105\108\101\100\058 \097 \114\101\115\111\117\114\099\101 \099\117\114\114\101\110\099\121 \099\097\110 \111\110\108\121 \098\101 \065-\090\044 \097-\122\046 \083\116\114\105\110\103 \119\097\115\058 "..L)return false end end return true end function j.validateResourceItemTypes(b,L)if not j:validateArrayOfStrings(20,32,false,"\114\101\115\111\117\114\099\101 \105\116\101\109 \116\121\112\101\115",L)then return false end for L,b in pairs(L)do if not j:validateEventPartCharacters(b)then c:w("\114\101\115\111\117\114\099\101 \105\116\101\109 \116\121\112\101\115 \118\097\108\105\100\097\116\105\111\110 \102\097\105\108\101\100\058 \097 \114\101\115\111\117\114\099\101 \105\116\101\109 \116\121\112\101 \099\097\110\110\111\116 \099\111\110\116\097\105\110 \111\116\104\101\114 \099\104\097\114\097\099\116\101\114\115 \116\104\097\110 \065-\122\044 \048-\057\044 -\095\046\044 \040\041\033\063\046 \083\116\114\105\110\103 \119\097\115\058 "..b)return false end end return true end function j.validateEventPartCharacters(c,j)if not string.find(j,"\094\091\065-\090\097-\122\048-\057\037\115\037-\095\037\046\037\040\037\041\033\037\063\093\043\036")then return false end return true end function j.validateArrayOfStrings(q,j,L,b,f,E)local Z=f if not Z then Z="\065\114\114\097\121"end if not E then c:w(Z.." \118\097\108\105\100\097\116\105\111\110 \102\097\105\108\101\100\058 \097\114\114\097\121 \099\097\110\110\111\116 \098\101 \110\105\108\046")return false end if not b and#E==0 then c:w(Z.." \118\097\108\105\100\097\116\105\111\110 \102\097\105\108\101\100\058 \097\114\114\097\121 \099\097\110\110\111\116 \098\101 \101\109\112\116\121\046")return false end if j>0 and#E>j then c:w(Z..(" \118\097\108\105\100\097\116\105\111\110 \102\097\105\108\101\100\058 \097\114\114\097\121 \099\097\110\110\111\116 \101\120\099\101\101\100 "..(tostring(j)..(" \118\097\108\117\101\115\046 \073\116 \104\097\115 "..(#E.." \118\097\108\117\101\115\046")))))return false end for j,b in ipairs(E)do local f=0 if b then f=#b end if f==0 then c:w(Z.." \118\097\108\105\100\097\116\105\111\110 \102\097\105\108\101\100\058 \099\111\110\116\097\105\110\101\100 \097\110 \101\109\112\116\121 \115\116\114\105\110\103\046")return false end if L>0 and f>L then c:w(Z..(" \118\097\108\105\100\097\116\105\111\110 \102\097\105\108\101\100\058 \097 \115\116\114\105\110\103 \101\120\099\101\101\100\101\100 \109\097\120 \097\108\108\111\119\101\100 \108\101\110\103\116\104 \040\119\104\105\099\104 \105\115\058 "..(tostring(L)..("\041\046 \083\116\114\105\110\103 \119\097\115\058 "..b))))return false end end return true end function j.validateBuild(L,c)if not j:validateShortString(c,false)then return false end return true end function j.validateShortString(b,j,c)if c and L:isStringNullOrEmpty(j)then return true end if L:isStringNullOrEmpty(j)or#j>32 then return false end return true end function j.validateKeys(L,j,c)if string.find(j,"\094\091\065-\090\097-\122\048-\057\093\043\036")and#j==32 then if string.find(c,"\094\091\065-\090\097-\122\048-\057\093\043\036")and#c==40 then return true end end return false end function j.validateAndCleanInitRequestResponse(b,j,L)if not j then c:w("\118\097\108\105\100\097\116\101\073\110\105\116\082\101\113\117\101\115\116\082\101\115\112\111\110\115\101 \102\097\105\108\101\100 - \110\111 \114\101\115\112\111\110\115\101 \100\105\099\116\105\111\110\097\114\121\046")return nil end local f={}local E=j.server_ts or-1 if E>0 then f.server_ts=E end if L then f.configs=j.configs or{}f.ab_id=j.ab_id or""f.ab_variant_id=j.ab_variant_id or""end return f end function j.validateClientTs(c,j)if j<1000000000 or j>9999999999 then return false end return true end function j.validateCurrency(c,j)if L:isStringNullOrEmpty(j)then return false end if string.find(j,"\094\091\065-\090\093\043\036")and#j==3 then return true end return false end function j.validateEventPartLength(b,j,c)if c and L:isStringNullOrEmpty(j)then return true end if L:isStringNullOrEmpty(j)then return false end if#j==0 or#j>64 then return false end return true end function j.validateBusinessEvent(Z,L,b,f,E,q)if not j:validateCurrency(L)then c:w("\086\097\108\105\100\097\116\105\111\110 \102\097\105\108 - \098\117\115\105\110\101\115\115 \101\118\101\110\116 - \099\117\114\114\101\110\099\121\058 \067\097\110\110\111\116 \098\101 \040\110\117\108\108\041 \097\110\100 \110\101\101\100 \116\111 \098\101 \065-\090\044 \051 \099\104\097\114\097\099\116\101\114\115 \097\110\100 \105\110 \116\104\101 \115\116\097\110\100\097\114\100 \097\116 \111\112\101\110\101\120\099\104\097\110\103\101\114\097\116\101\115\046\111\114\103\046 \070\097\105\108\101\100 \099\117\114\114\101\110\099\121\058 "..L)return false end if b<0 then c:w("\086\097\108\105\100\097\116\105\111\110 \102\097\105\108 - \098\117\115\105\110\101\115\115 \101\118\101\110\116 - \097\109\111\117\110\116\058 \067\097\110\110\111\116 \098\101 \108\101\115\115 \116\104\101\110 \048\046 \070\097\105\108\101\100 \097\109\111\117\110\116\058 "..b)return false end if not j:validateShortString(f,true)then c:w("\086\097\108\105\100\097\116\105\111\110 \102\097\105\108 - \098\117\115\105\110\101\115\115 \101\118\101\110\116 - \099\097\114\116\084\121\112\101\046 \067\097\110\110\111\116 \098\101 \097\098\111\118\101 \051\050 \108\101\110\103\116\104\046 \083\116\114\105\110\103\058 "..f)return false end if not j:validateEventPartLength(E,false)then c:w("\086\097\108\105\100\097\116\105\111\110 \102\097\105\108 - \098\117\115\105\110\101\115\115 \101\118\101\110\116 - \105\116\101\109\084\121\112\101\058 \067\097\110\110\111\116 \098\101 \040\110\117\108\108\041\044 \101\109\112\116\121 \111\114 \097\098\111\118\101 \054\052 \099\104\097\114\097\099\116\101\114\115\046 \083\116\114\105\110\103\058 "..E)return false end if not j:validateEventPartCharacters(E)then c:w("\086\097\108\105\100\097\116\105\111\110 \102\097\105\108 - \098\117\115\105\110\101\115\115 \101\118\101\110\116 - \105\116\101\109\084\121\112\101\058 \067\097\110\110\111\116 \099\111\110\116\097\105\110 \111\116\104\101\114 \099\104\097\114\097\099\116\101\114\115 \116\104\097\110 \065-\122\044 \048-\057\044 -\095\046\044 \040\041\033\063\046 \083\116\114\105\110\103\058 "..E)return false end if not j:validateEventPartLength(q,false)then c:w("\086\097\108\105\100\097\116\105\111\110 \102\097\105\108 - \098\117\115\105\110\101\115\115 \101\118\101\110\116 - \105\116\101\109\073\100\046 \067\097\110\110\111\116 \098\101 \040\110\117\108\108\041\044 \101\109\112\116\121 \111\114 \097\098\111\118\101 \054\052 \099\104\097\114\097\099\116\101\114\115\046 \083\116\114\105\110\103\058 "..q)return false end if not j:validateEventPartCharacters(q)then c:w("\086\097\108\105\100\097\116\105\111\110 \102\097\105\108 - \098\117\115\105\110\101\115\115 \101\118\101\110\116 - \105\116\101\109\073\100\058 \067\097\110\110\111\116 \099\111\110\116\097\105\110 \111\116\104\101\114 \099\104\097\114\097\099\116\101\114\115 \116\104\097\110 \065-\122\044 \048-\057\044 -\095\046\044 \040\041\033\063\046 \083\116\114\105\110\103\058 "..q)return false end return true end function j.validateResourceEvent(y,b,f,E,q,Z,r,o,G)if f~=b.Source and f~=b.Sink then c:w("\086\097\108\105\100\097\116\105\111\110 \102\097\105\108 - \114\101\115\111\117\114\099\101 \101\118\101\110\116 - \102\108\111\119\084\121\112\101\058 \073\110\118\097\108\105\100 \102\108\111\119 \116\121\112\101 "..tostring(f))return false end if L:isStringNullOrEmpty(E)then c:w("\086\097\108\105\100\097\116\105\111\110 \102\097\105\108 - \114\101\115\111\117\114\099\101 \101\118\101\110\116 - \099\117\114\114\101\110\099\121\058 \067\097\110\110\111\116 \098\101 \040\110\117\108\108\041")return false end if not L:stringArrayContainsString(o,E)then c:w("\086\097\108\105\100\097\116\105\111\110 \102\097\105\108 - \114\101\115\111\117\114\099\101 \101\118\101\110\116 - \099\117\114\114\101\110\099\121\058 \078\111\116 \102\111\117\110\100 \105\110 \108\105\115\116 \111\102 \112\114\101-\100\101\102\105\110\101\100 \097\118\097\105\108\097\098\108\101 \114\101\115\111\117\114\099\101 \099\117\114\114\101\110\099\105\101\115\046 \083\116\114\105\110\103\058 "..E)return false end if not(q>0)then c:w("\086\097\108\105\100\097\116\105\111\110 \102\097\105\108 - \114\101\115\111\117\114\099\101 \101\118\101\110\116 - \097\109\111\117\110\116\058 \070\108\111\097\116 \097\109\111\117\110\116 \099\097\110\110\111\116 \098\101 \048 \111\114 \110\101\103\097\116\105\118\101\046 \086\097\108\117\101\058 "..tostring(q))return false end if L:isStringNullOrEmpty(Z)then c:w("\086\097\108\105\100\097\116\105\111\110 \102\097\105\108 - \114\101\115\111\117\114\099\101 \101\118\101\110\116 - \105\116\101\109\084\121\112\101\058 \067\097\110\110\111\116 \098\101 \040\110\117\108\108\041")return false end if not j:validateEventPartLength(Z,false)then c:w("\086\097\108\105\100\097\116\105\111\110 \102\097\105\108 - \114\101\115\111\117\114\099\101 \101\118\101\110\116 - \105\116\101\109\084\121\112\101\058 \067\097\110\110\111\116 \098\101 \040\110\117\108\108\041\044 \101\109\112\116\121 \111\114 \097\098\111\118\101 \054\052 \099\104\097\114\097\099\116\101\114\115\046 \083\116\114\105\110\103\058 "..Z)return false end if not j:validateEventPartCharacters(Z)then c:w("\086\097\108\105\100\097\116\105\111\110 \102\097\105\108 - \114\101\115\111\117\114\099\101 \101\118\101\110\116 - \105\116\101\109\084\121\112\101\058 \067\097\110\110\111\116 \099\111\110\116\097\105\110 \111\116\104\101\114 \099\104\097\114\097\099\116\101\114\115 \116\104\097\110 \065-\122\044 \048-\057\044 -\095\046\044 \040\041\033\063\046 \083\116\114\105\110\103\058 "..Z)return false end if not L:stringArrayContainsString(G,Z)then c:w("\086\097\108\105\100\097\116\105\111\110 \102\097\105\108 - \114\101\115\111\117\114\099\101 \101\118\101\110\116 - \105\116\101\109\084\121\112\101\058 \078\111\116 \102\111\117\110\100 \105\110 \108\105\115\116 \111\102 \112\114\101-\100\101\102\105\110\101\100 \097\118\097\105\108\097\098\108\101 \114\101\115\111\117\114\099\101 \105\116\101\109\084\121\112\101\115\046 \083\116\114\105\110\103\058 "..Z)return false end if not j:validateEventPartLength(r,false)then c:w("\086\097\108\105\100\097\116\105\111\110 \102\097\105\108 - \114\101\115\111\117\114\099\101 \101\118\101\110\116 - \105\116\101\109\073\100\058 \067\097\110\110\111\116 \098\101 \040\110\117\108\108\041\044 \101\109\112\116\121 \111\114 \097\098\111\118\101 \054\052 \099\104\097\114\097\099\116\101\114\115\046 \083\116\114\105\110\103\058 "..r)return false end if not j:validateEventPartCharacters(r)then c:w("\086\097\108\105\100\097\116\105\111\110 \102\097\105\108 - \114\101\115\111\117\114\099\101 \101\118\101\110\116 - \105\116\101\109\073\100\058 \067\097\110\110\111\116 \099\111\110\116\097\105\110 \111\116\104\101\114 \099\104\097\114\097\099\116\101\114\115 \116\104\097\110 \065-\122\044 \048-\057\044 -\095\046\044 \040\041\033\063\046 \083\116\114\105\110\103\058 "..r)return false end return true end function j.validateProgressionEvent(r,b,f,E,q,Z)if f~=b.Start and(f~=b.Complete and f~=b.Fail)then c:w("\086\097\108\105\100\097\116\105\111\110 \102\097\105\108 - \112\114\111\103\114\101\115\115\105\111\110 \101\118\101\110\116\058 \073\110\118\097\108\105\100 \112\114\111\103\114\101\115\115\105\111\110 \115\116\097\116\117\115 "..tostring(f))return false end if not L:isStringNullOrEmpty(Z)and not(not L:isStringNullOrEmpty(q)or L:isStringNullOrEmpty(E))then c:w("\086\097\108\105\100\097\116\105\111\110 \102\097\105\108 - \112\114\111\103\114\101\115\115\105\111\110 \101\118\101\110\116\058 \048\051 \102\111\117\110\100 \098\117\116 \048\049\043\048\050 \097\114\101 \105\110\118\097\108\105\100\046 \080\114\111\103\114\101\115\115\105\111\110 \109\117\115\116 \098\101 \115\101\116 \097\115 \101\105\116\104\101\114 \048\049\044 \048\049\043\048\050 \111\114 \048\049\043\048\050\043\048\051\046")return false elseif not L:isStringNullOrEmpty(q)and L:isStringNullOrEmpty(E)then c:w("\086\097\108\105\100\097\116\105\111\110 \102\097\105\108 - \112\114\111\103\114\101\115\115\105\111\110 \101\118\101\110\116\058 \048\050 \102\111\117\110\100 \098\117\116 \110\111\116 \048\049\046 \080\114\111\103\114\101\115\115\105\111\110 \109\117\115\116 \098\101 \115\101\116 \097\115 \101\105\116\104\101\114 \048\049\044 \048\049\043\048\050 \111\114 \048\049\043\048\050\043\048\051")return false elseif L:isStringNullOrEmpty(E)then c:w("\086\097\108\105\100\097\116\105\111\110 \102\097\105\108 - \112\114\111\103\114\101\115\115\105\111\110 \101\118\101\110\116\058 \112\114\111\103\114\101\115\115\105\111\110\048\049 \110\111\116 \118\097\108\105\100\046 \080\114\111\103\114\101\115\115\105\111\110\115 \109\117\115\116 \098\101 \115\101\116 \097\115 \101\105\116\104\101\114 \048\049\044 \048\049\043\048\050 \111\114 \048\049\043\048\050\043\048\051")return false end if not j:validateEventPartLength(E,false)then c:w("\086\097\108\105\100\097\116\105\111\110 \102\097\105\108 - \112\114\111\103\114\101\115\115\105\111\110 \101\118\101\110\116 - \112\114\111\103\114\101\115\115\105\111\110\048\049\058 \067\097\110\110\111\116 \098\101 \040\110\117\108\108\041\044 \101\109\112\116\121 \111\114 \097\098\111\118\101 \054\052 \099\104\097\114\097\099\116\101\114\115\046 \083\116\114\105\110\103\058 "..E)return false end if not j:validateEventPartCharacters(E)then c:w("\086\097\108\105\100\097\116\105\111\110 \102\097\105\108 - \112\114\111\103\114\101\115\115\105\111\110 \101\118\101\110\116 - \112\114\111\103\114\101\115\115\105\111\110\048\049\058 \067\097\110\110\111\116 \099\111\110\116\097\105\110 \111\116\104\101\114 \099\104\097\114\097\099\116\101\114\115 \116\104\097\110 \065-\122\044 \048-\057\044 -\095\046\044 \040\041\033\063\046 \083\116\114\105\110\103\058 "..E)return false end if not L:isStringNullOrEmpty(q)then if not j:validateEventPartLength(q,false)then c:w("\086\097\108\105\100\097\116\105\111\110 \102\097\105\108 - \112\114\111\103\114\101\115\115\105\111\110 \101\118\101\110\116 - \112\114\111\103\114\101\115\115\105\111\110\048\050\058 \067\097\110\110\111\116 \098\101 \101\109\112\116\121 \111\114 \097\098\111\118\101 \054\052 \099\104\097\114\097\099\116\101\114\115\046 \083\116\114\105\110\103\058 "..q)return false end if not j:validateEventPartCharacters(q)then c:w("\086\097\108\105\100\097\116\105\111\110 \102\097\105\108 - \112\114\111\103\114\101\115\115\105\111\110 \101\118\101\110\116 - \112\114\111\103\114\101\115\115\105\111\110\048\050\058 \067\097\110\110\111\116 \099\111\110\116\097\105\110 \111\116\104\101\114 \099\104\097\114\097\099\116\101\114\115 \116\104\097\110 \065-\122\044 \048-\057\044 -\095\046\044 \040\041\033\063\046 \083\116\114\105\110\103\058 "..q)return false end end if not L:isStringNullOrEmpty(Z)then if not j:validateEventPartLength(Z,false)then c:w("\086\097\108\105\100\097\116\105\111\110 \102\097\105\108 - \112\114\111\103\114\101\115\115\105\111\110 \101\118\101\110\116 - \112\114\111\103\114\101\115\115\105\111\110\048\051\058 \067\097\110\110\111\116 \098\101 \101\109\112\116\121 \111\114 \097\098\111\118\101 \054\052 \099\104\097\114\097\099\116\101\114\115\046 \083\116\114\105\110\103\058 "..Z)return false end if not j:validateEventPartCharacters(Z)then c:w("\086\097\108\105\100\097\116\105\111\110 \102\097\105\108 - \112\114\111\103\114\101\115\115\105\111\110 \101\118\101\110\116 - \112\114\111\103\114\101\115\115\105\111\110\048\051\058 \067\097\110\110\111\116 \099\111\110\116\097\105\110 \111\116\104\101\114 \099\104\097\114\097\099\116\101\114\115 \116\104\097\110 \065-\122\044 \048-\057\044 -\095\046\044 \040\041\033\063\046 \083\116\114\105\110\103\058 "..Z)return false end end return true end function j.validateEventIdLength(c,j)if L:isStringNullOrEmpty(j)then return false end local b=0 for j in string.gmatch(j,"\040\091\094\058\093\043\041")do b=b+1 if b>5 or#j>64 then return false end end return true end function j.validateEventIdCharacters(c,j)if L:isStringNullOrEmpty(j)then return false end local b=0 for j in string.gmatch(j,"\040\091\094\058\093\043\041")do b=b+1 if b>5 or not string.find(j,"\094\091\065-\090\097-\122\048-\057\037\115\037-\095\037\046\037\040\037\041\033\037\063\093\043\036")then return false end end return true end function j.validateDesignEvent(b,L)if not j:validateEventIdLength(L)then c:w("\086\097\108\105\100\097\116\105\111\110 \102\097\105\108 - \100\101\115\105\103\110 \101\118\101\110\116 - \101\118\101\110\116\073\100\058 \067\097\110\110\111\116 \098\101 \040\110\117\108\108\041 \111\114 \101\109\112\116\121\046 \079\110\108\121 \053 \101\118\101\110\116 \112\097\114\116\115 \097\108\108\111\119\101\100 \115\101\112\101\114\097\116\101\100 \098\121 \058\046 \069\097\099\104 \112\097\114\116 \110\101\101\100 \116\111 \098\101 \051\050 \099\104\097\114\097\099\116\101\114\115 \111\114 \108\101\115\115\046 \083\116\114\105\110\103\058 "..L)return false end if not j:validateEventIdCharacters(L)then c:w("\086\097\108\105\100\097\116\105\111\110 \102\097\105\108 - \100\101\115\105\103\110 \101\118\101\110\116 - \101\118\101\110\116\073\100\058 \078\111\110 \118\097\108\105\100 \099\104\097\114\097\099\116\101\114\115\046 \079\110\108\121 \097\108\108\111\119\101\100 \065-\122\044 \048-\057\044 -\095\046\044 \040\041\033\063\046 \083\116\114\105\110\103\058 "..L)return false end return true end function j.validateLongString(b,j,c)if c and L:isStringNullOrEmpty(j)then return true end if L:isStringNullOrEmpty(j)or#j>8192 then return false end return true end function j.validateErrorEvent(E,L,b,f)if b~=L.debug and(b~=L.info and(b~=L.warning and(b~=L.error and b~=L.critical)))then c:w("\086\097\108\105\100\097\116\105\111\110 \102\097\105\108 - \101\114\114\111\114 \101\118\101\110\116 - \115\101\118\101\114\105\116\121\058 \083\101\118\101\114\105\116\121 \119\097\115 \117\110\115\117\112\112\111\114\116\101\100 \118\097\108\117\101 "..tostring(b))return false end if not j:validateLongString(f,true)then c:w("\086\097\108\105\100\097\116\105\111\110 \102\097\105\108 - \101\114\114\111\114 \101\118\101\110\116 - \109\101\115\115\097\103\101\058 \077\101\115\115\097\103\101 \099\097\110\110\111\116 \098\101 \097\098\111\118\101 \056\049\057\050 \099\104\097\114\097\099\116\101\114\115\046")return false end return true end return j
local validation = {}

local logger = require(script.Parent.Logger)
local utilities = require(script.Parent.Utilities)

function validation:validateCustomDimensions(customDimensions)
	return validation:validateArrayOfStrings(20, 32, false, "custom dimensions", customDimensions)
end

function validation:validateDimension(dimensions, dimension)
	-- allow nil
	if utilities:isStringNullOrEmpty(dimension) then
		return true
	end

	if not utilities:stringArrayContainsString(dimensions, dimension) then
		return false
	end

	return true
end

function validation:validateResourceCurrencies(resourceCurrencies)
	if not validation:validateArrayOfStrings(20, 64, false, "resource currencies", resourceCurrencies) then
		return false
	end

	-- validate each string for regex
	for _, resourceCurrency in pairs(resourceCurrencies) do
		if not string.find(resourceCurrency, "^[A-Za-z]+$") then
			logger:w("resource currencies validation failed: a resource currency can only be A-Z, a-z. String was: " .. resourceCurrency)
			return false
		end
	end

	return true
end

function validation:validateResourceItemTypes(resourceItemTypes)
	if not validation:validateArrayOfStrings(20, 32, false, "resource item types", resourceItemTypes) then
		return false
	end

	-- validate each string for regex
	for _, resourceItemType in pairs(resourceItemTypes) do
		if not validation:validateEventPartCharacters(resourceItemType) then
			logger:w("resource item types validation failed: a resource item type cannot contain other characters than A-z, 0-9, -_., ()!?. String was: " .. resourceItemType)
			return false
		end
	end

	return true
end

function validation:validateEventPartCharacters(eventPart)
	if not string.find(eventPart, "^[A-Za-z0-9%s%-_%.%(%)!%?]+$") then
		return false
	end

	return true
end

function validation:validateArrayOfStrings(maxCount, maxStringLength, allowNoValues, logTag, arrayOfStrings)
	local arrayTag = logTag

	if not arrayTag then
		arrayTag = "Array"
	end

	-- use arrayTag to annotate warning log
	if not arrayOfStrings then
		logger:w(arrayTag .. " validation failed: array cannot be nil.")
		return false
	end

	-- check if empty
	if not allowNoValues and #arrayOfStrings == 0 then
		logger:w(arrayTag .. " validation failed: array cannot be empty.")
		return false
	end

	-- check if exceeding max count
	if maxCount > 0 and #arrayOfStrings > maxCount then
		logger:w(arrayTag .. " validation failed: array cannot exceed " .. tostring(maxCount) .. " values. It has " .. #arrayOfStrings .. " values.")
		return false
	end

	-- validate each string
	for _, arrayString in ipairs(arrayOfStrings) do
		local stringLength = 0
		if arrayString then
			stringLength = #arrayString
		end

		-- check if empty (not allowed)
		if stringLength == 0 then
			logger:w(arrayTag .. " validation failed: contained an empty string.")
			return false
		end

		-- check if exceeding max length
		if maxStringLength > 0 and stringLength > maxStringLength then
			logger:w(arrayTag .. " validation failed: a string exceeded max allowed length (which is: " .. tostring(maxStringLength) .. "). String was: " .. arrayString)
			return false
		end
	end

	return true
end

function validation:validateBuild(build)
	if not validation:validateShortString(build, false) then
		return false
	end

	return true
end

function validation:validateShortString(shortString, canBeEmpty)
	-- String is allowed to be empty or nil
	if canBeEmpty and utilities:isStringNullOrEmpty(shortString) then
		return true
	end

	if utilities:isStringNullOrEmpty(shortString) or #shortString > 32 then
		return false
	end

	return true
end

function validation:validateKeys(gameKey, secretKey)
	if string.find(gameKey, "^[A-Za-z0-9]+$") and #gameKey == 32 then
		if string.find(secretKey, "^[A-Za-z0-9]+$") and #secretKey == 40 then
			return true
		end
	end

	return false
end

function validation:validateAndCleanInitRequestResponse(initResponse, configsCreated)
	-- make sure we have a valid dict
	if not initResponse then
		logger:w("validateInitRequestResponse failed - no response dictionary.")
		return nil
	end

	local validatedDict = {}

	-- validate server_ts
	local serverTsNumber = initResponse["server_ts"] or -1
	if serverTsNumber > 0 then
		validatedDict["server_ts"] = serverTsNumber
	end

	if configsCreated then
		validatedDict["configs"] = initResponse["configs"] or {}
		validatedDict["ab_id"] = initResponse["ab_id"] or ""
		validatedDict["ab_variant_id"] = initResponse["ab_variant_id"] or ""
	end

	return validatedDict
end

function validation:validateClientTs(clientTs)
	if clientTs < 1000000000 or clientTs > 9999999999 then
		return false
	end

	return true
end

function validation:validateCurrency(currency)
	if utilities:isStringNullOrEmpty(currency) then
		return false
	end

	if string.find(currency, "^[A-Z]+$") and #currency == 3 then
		return true
	end

	return false
end

function validation:validateEventPartLength(eventPart, allowNull)
	if allowNull and utilities:isStringNullOrEmpty(eventPart) then
		return true
	end

	if utilities:isStringNullOrEmpty(eventPart) then
		return false
	end

	if #eventPart == 0 or #eventPart > 64 then
		return false
	end
	return true
end

function validation:validateBusinessEvent(currency, amount, cartType, itemType, itemId)
	-- validate currency
	if not validation:validateCurrency(currency) then
		logger:w("Validation fail - business event - currency: Cannot be (null) and need to be A-Z, 3 characters and in the standard at openexchangerates.org. Failed currency: " .. currency)
		return false
	end

	if amount < 0 then
		logger:w("Validation fail - business event - amount: Cannot be less then 0. Failed amount: " .. amount)
		return false
	end

	-- validate cartType
	if not validation:validateShortString(cartType, true) then
		logger:w("Validation fail - business event - cartType. Cannot be above 32 length. String: " .. cartType)
		return false
	end

	-- validate itemType length
	if not validation:validateEventPartLength(itemType, false) then
		logger:w("Validation fail - business event - itemType: Cannot be (null), empty or above 64 characters. String: " .. itemType)
		return false
	end

	-- validate itemType chars
	if not validation:validateEventPartCharacters(itemType) then
		logger:w("Validation fail - business event - itemType: Cannot contain other characters than A-z, 0-9, -_., ()!?. String: " .. itemType)
		return false
	end

	-- validate itemId
	if not validation:validateEventPartLength(itemId, false) then
		logger:w("Validation fail - business event - itemId. Cannot be (null), empty or above 64 characters. String: " .. itemId)
		return false
	end

	if not validation:validateEventPartCharacters(itemId) then
		logger:w("Validation fail - business event - itemId: Cannot contain other characters than A-z, 0-9, -_., ()!?. String: " .. itemId)
		return false
	end

	return true
end

function validation:validateResourceEvent(flowTypeValues, flowType, currency, amount, itemType, itemId, currencies, itemTypes)
	if flowType ~= flowTypeValues.Source and flowType ~= flowTypeValues.Sink then
		logger:w("Validation fail - resource event - flowType: Invalid flow type " .. tostring(flowType))
		return false
	end

	if utilities:isStringNullOrEmpty(currency) then
		logger:w("Validation fail - resource event - currency: Cannot be (null)")
		return false
	end

	if not utilities:stringArrayContainsString(currencies, currency) then
		logger:w("Validation fail - resource event - currency: Not found in list of pre-defined available resource currencies. String: " .. currency)
		return false
	end

	if not (amount > 0) then
		logger:w("Validation fail - resource event - amount: Float amount cannot be 0 or negative. Value: " .. tostring(amount))
		return false
	end

	if utilities:isStringNullOrEmpty(itemType) then
		logger:w("Validation fail - resource event - itemType: Cannot be (null)")
		return false
	end

	if not validation:validateEventPartLength(itemType, false) then
		logger:w("Validation fail - resource event - itemType: Cannot be (null), empty or above 64 characters. String: " .. itemType)
		return false
	end

	if not validation:validateEventPartCharacters(itemType) then
		logger:w("Validation fail - resource event - itemType: Cannot contain other characters than A-z, 0-9, -_., ()!?. String: " .. itemType)
		return false
	end

	if not utilities:stringArrayContainsString(itemTypes, itemType) then
		logger:w("Validation fail - resource event - itemType: Not found in list of pre-defined available resource itemTypes. String: " .. itemType)
		return false
	end

	if not validation:validateEventPartLength(itemId, false) then
		logger:w("Validation fail - resource event - itemId: Cannot be (null), empty or above 64 characters. String: " .. itemId)
		return false
	end

	if not validation:validateEventPartCharacters(itemId) then
		logger:w("Validation fail - resource event - itemId: Cannot contain other characters than A-z, 0-9, -_., ()!?. String: " .. itemId)
		return false
	end

	return true
end

function validation:validateProgressionEvent(progressionStatusValues, progressionStatus, progression01, progression02, progression03)
	if progressionStatus ~= progressionStatusValues.Start and progressionStatus ~= progressionStatusValues.Complete and progressionStatus ~= progressionStatusValues.Fail then
		logger:w("Validation fail - progression event: Invalid progression status " .. tostring(progressionStatus))
		return false
	end

	-- Make sure progressions are defined as either 01, 01+02 or 01+02+03
	if not utilities:isStringNullOrEmpty(progression03) and not (not utilities:isStringNullOrEmpty(progression02) or utilities:isStringNullOrEmpty(progression01)) then
		logger:w("Validation fail - progression event: 03 found but 01+02 are invalid. Progression must be set as either 01, 01+02 or 01+02+03.")
		return false
	elseif not utilities:isStringNullOrEmpty(progression02) and utilities:isStringNullOrEmpty(progression01) then
		logger:w("Validation fail - progression event: 02 found but not 01. Progression must be set as either 01, 01+02 or 01+02+03")
		return false
	elseif utilities:isStringNullOrEmpty(progression01) then
		logger:w("Validation fail - progression event: progression01 not valid. Progressions must be set as either 01, 01+02 or 01+02+03")
		return false
	end

	-- progression01 (required)
	if not validation:validateEventPartLength(progression01, false) then
		logger:w("Validation fail - progression event - progression01: Cannot be (null), empty or above 64 characters. String: " .. progression01)
		return false
	end

	if not validation:validateEventPartCharacters(progression01) then
		logger:w("Validation fail - progression event - progression01: Cannot contain other characters than A-z, 0-9, -_., ()!?. String: " .. progression01)
		return false
	end

	-- progression02
	if not utilities:isStringNullOrEmpty(progression02) then
		if not validation:validateEventPartLength(progression02, false) then
			logger:w("Validation fail - progression event - progression02: Cannot be empty or above 64 characters. String: " .. progression02)
			return false
		end

		if not validation:validateEventPartCharacters(progression02) then
			logger:w("Validation fail - progression event - progression02: Cannot contain other characters than A-z, 0-9, -_., ()!?. String: " .. progression02)
			return false
		end
	end

	-- progression03
	if not utilities:isStringNullOrEmpty(progression03) then
		if not validation:validateEventPartLength(progression03, false) then
			logger:w("Validation fail - progression event - progression03: Cannot be empty or above 64 characters. String: " .. progression03)
			return false
		end

		if not validation:validateEventPartCharacters(progression03) then
			logger:w("Validation fail - progression event - progression03: Cannot contain other characters than A-z, 0-9, -_., ()!?. String: " .. progression03)
			return false
		end
	end

	return true
end

function validation:validateEventIdLength(eventId)
	if utilities:isStringNullOrEmpty(eventId) then
		return false
	end

	local count = 0
	for s in string.gmatch(eventId, "([^:]+)") do
		count = count + 1
		if count > 5 or #s > 64 then
			return false
		end
	end

	return true
end

function validation:validateEventIdCharacters(eventId)
	if utilities:isStringNullOrEmpty(eventId) then
		return false
	end

	local count = 0
	for s in string.gmatch(eventId, "([^:]+)") do
		count = count + 1
		if count > 5 or not string.find(s, "^[A-Za-z0-9%s%-_%.%(%)!%?]+$") then
			return false
		end
	end

	return true
end

function validation:validateDesignEvent(eventId)
	if not validation:validateEventIdLength(eventId) then
		logger:w("Validation fail - design event - eventId: Cannot be (null) or empty. Only 5 event parts allowed seperated by :. Each part need to be 32 characters or less. String: " .. eventId)
		return false
	end

	if not validation:validateEventIdCharacters(eventId) then
		logger:w("Validation fail - design event - eventId: Non valid characters. Only allowed A-z, 0-9, -_., ()!?. String: " .. eventId)
		return false
	end

	-- value: allow 0, negative and nil (not required)
	return true
end

function validation:validateLongString(longString, canBeEmpty)
	-- String is allowed to be empty
	if canBeEmpty and utilities:isStringNullOrEmpty(longString) then
		return true
	end

	if utilities:isStringNullOrEmpty(longString) or #longString > 8192 then
		return false
	end

	return true
end

function validation:validateErrorEvent(severityValues, severity, message)
	if severity ~= severityValues.debug and severity ~= severityValues.info and severity ~= severityValues.warning and severity ~= severityValues.error and severity ~= severityValues.critical then
		logger:w("Validation fail - error event - severity: Severity was unsupported value " .. tostring(severity))
		return false
	end

	if not validation:validateLongString(message, true) then
		logger:w("Validation fail - error event - message: Message cannot be above 8192 characters.")
		return false
	end

	return true
end

return validation
