const {body, validationResult} = require('express-validator')
const v_m = require('../validation_messages')

const validationMessages = {
  fa: {
    method: 'روش محاسبه را انتخاب کنید',
    method_not_supported: 'روش انتخاب شده پشتیبانی نشده است',
    gratingType: 'نوع گریتینک را انتخاب کنید',
    gratingType_not_supported: 'نوع گریتینگ پشتیبانی نشده است',
    loadType: 'نوع فشار را وارد کنید',
    class: 'کلاس را انتخاب کنید',
    pointedLoad: 'مقدار بار متمرکز را وارد کنید',
    distributedLoad: 'مقدار بار گسترده را وارد کنید',
    bearingBarThickness: 'ضخامت تسمه باربر را وارد کنید',
    crossBarThickness: 'ضخامت تسمه رابط را وارد کنید',
    bearingBarPitch: 'گام تسمه باربر را انتخاب کنید',
    bearingBarPitch_not_ok: 'مقدار گام تسمه باربر صحیح نیست',
    crossBarPitch: 'گام تسمه رابط را تنخاب کنید',
    crossBarPitch_not_ok: 'مقدار گام تسمه رابط صحیح نیست',
    bearingBarHeight: 'ارتفاع تسمه باربر را انتخاب کنید',
    crossBarHeight: 'ارتفاع تسمه رابط را وارد کنید',
    bearingBarHeight_not_ok: 'مقدار ارتفاع تسمه باربر صحیح نیست',
    clearSpan: 'مقدار دهنه را وارد کنید',
    sigma_ok: 'تنش مجاز',
    sigma_out_of_range: 'تنش خارج از حد مجاز',
    deflection_ok: 'خیز مجاز',
    deflection_out_of_range: 'خیز خارج از حد مجاز'
  },
  en: {
    method: 'Choose calculation method',
    method_not_supported: 'Chosen calculation method not supported',
    gratingType: 'Select the type of grating',
    gratingType_not_supported: 'Grating type not supported',
    loadType: 'Enter load type',
    class: 'Select class',
    pointedLoad: 'Enter the amount of pointed load',
    distributedLoad: 'Enter the amount of distributed load',
    bearingBarThickness: 'Enter bearing bar thickness',
    crossBarThickness: 'Enter cross bar thickness',
    bearingBarPitch: 'Select bearing bar pitch',
    bearingBarPitch_not_ok: 'Bearing bar pitch value is incorrect',
    crossBarPitch: 'Select cross bar pitch',
    crossBarPitch_not_ok: 'Cross bar pitch value is incorrect',
    bearingBarHeight: 'Select bearing bar height',
    crossBarHeight: 'Enter cross bar height',
    bearingBarHeight_not_ok: 'Bearing bar height is incorrect',
    clearSpan: 'Enter clear span',
    sigma_ok: 'Tension OK',
    sigma_out_of_range: 'Tension Out Of Range',
    deflection_ok: 'Deflection OK',
    deflection_out_of_range: 'Deflection Out Of Range'
  }
}

const values = {
  // ArakRail products
  bearingBarPitch_forge: [30, 35, 41, 50],
  bearingBarPitch_pressured: [11, 22, 33, 44, 50, 55],
  // defined in formula
  crossBarPitch_forge: [38, 50, 76, 100],
  crossBarPitch_pressured: [11, 22, 33, 44, 50, 55, 66, 77, 88, 100],
  // defined in formula
  bearingBarHeight: [20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80, 85, 90, 95, 100]
}

function relativeBearingBarHeight(gratingType, crossBarPitch) {
  // defined in formula
  bearingBarHeight = values.bearingBarHeight
  const CBPitch = Number(crossBarPitch)

  if (gratingType === 'forge') {
    if (CBPitch === 38) return bearingBarHeight.filter(item => item <= 80)
    else return bearingBarHeight.filter(item => item <= 60)
  } else if (gratingType === 'pressured') {
    if (
       CBPitch === 11 ||
       CBPitch === 22 ||
       CBPitch === 55 ||
       CBPitch === 77 ||
       CBPitch === 88
    ) return bearingBarHeight.filter(item => item <= 60)
    else if (
       CBPitch === 33 ||
       CBPitch === 44 ||
       CBPitch === 50 ||
       CBPitch === 66 ||
       CBPitch === 100
    ) return bearingBarHeight
  }
}

module.exports.calculate = [
  [
    body('method')
       .notEmpty().withMessage((value, {req}) => {
      return validationMessages[req.body.locale].method
    })
       .bail()
       .custom((value, {req}) => {
         if (value === 'custom' || value === 'classified') return true
         else return Promise.reject(validationMessages[req.body.locale].method_not_supported)
       }),
    body('gratingType')
       .notEmpty().withMessage((value, {req}) => {
      return validationMessages[req.body.locale].gratingType
    })
       .bail()
       .custom((value, {req}) => {
         if (value === 'forge' || value === 'pressured') return true
         else return Promise.reject(validationMessages[req.body.locale].gratingType_not_supported)
       }),
    body('loadType')
       .custom((value, {req}) => {
         if (req.body.method === 'custom') {
           if (value === 'pointedLoad' || value === 'distributedLoad') return true
           else return Promise.reject(validationMessages[req.body.locale].loadType)
         } else return true
       }),
    body('vehicleClass')
       .custom((value, {req}) => {
         if (req.body.method === 'classified') {
           const classes = ['class1', 'class2', 'class3', 'class4', 'FL1', 'FL2', 'FL3', 'FL4', 'FL5', 'FL6']
           if (classes.includes(value)) return true
           else return Promise.reject(validationMessages[req.body.locale].class)
         } else return true
       }),
    body('pointedLoadValue')
       .custom((value, {req}) => {
         if (req.body.method === 'custom') {
           if (req.body.loadType === 'pointedLoad' && !value) return Promise.reject(validationMessages[req.body.locale].pointedLoad)
           else return true
         } else return true
       })
       .bail()
       .if((value, {req}) => req.body.method === 'custom' && req.body.loadType === 'pointedLoad')
       .isNumeric().withMessage((value, {req}) => {
      return v_m[req.body.locale].format.number
    }),
    body('distributedLoadValue')
       .custom((value, {req}) => {
         if (req.body.method === 'custom') {
           if (req.body.loadType === 'distributedLoad' && !value) return Promise.reject(validationMessages[req.body.locale].distributedLoad)
           else return true
         } else return true
       })
       .bail()
       .if((value, {req}) => req.body.method === 'custom' && req.body.loadType === 'distributedLoad')
       .isNumeric().withMessage((value, {req}) => {
      return v_m[req.body.locale].format.number
    }),
    body('bearingBarThickness')
       .notEmpty().withMessage((value, {req}) => {
      return validationMessages[req.body.locale].bearingBarThickness
    })
       .bail()
       .isNumeric().withMessage((value, {req}) => {
      return v_m[req.body.locale].format.number
    }),


    body('bearingBarPitch')
       .notEmpty().withMessage((value, {req}) => {
      return validationMessages[req.body.locale].bearingBarPitch
    })
       .bail()
       .isNumeric().withMessage((value, {req}) => {
      return v_m[req.body.locale].format.number
    })
       .bail()
       .custom((value, {req}) => {
         if (req.body.gratingType === 'forge') {
           if (values.bearingBarPitch_forge.includes(Number(value))) return true
           else return Promise.reject(validationMessages[req.body.locale].bearingBarPitch_not_ok)
         } else {
           if (values.bearingBarPitch_pressured.includes(Number(value))) return true
           else return Promise.reject(validationMessages[req.body.locale].bearingBarPitch_not_ok)
         }
       }),

    body('crossBarPitch')
       .notEmpty().withMessage((value, {req}) => {
      return validationMessages[req.body.locale].crossBarPitch
    })
       .bail()
       .isNumeric().withMessage((value, {req}) => {
      return v_m[req.body.locale].format.number
    })
       .bail()
       .custom((value, {req}) => {
         if (req.body.gratingType === 'forge') {
           if (values.crossBarPitch_forge.includes(Number(value))) return true
           else return Promise.reject(validationMessages[req.body.locale].crossBarPitch_not_ok)
         } else {
           if (values.crossBarPitch_pressured.includes(Number(value))) return true
           else return Promise.reject(validationMessages[req.body.locale].crossBarPitch_not_ok)
         }
       }),

    body('bearingBarHeight')
       .notEmpty().withMessage((value, {req}) => {
      return validationMessages[req.body.locale].bearingBarHeight
    })
       .bail()
       .isNumeric().withMessage((value, {req}) => {
      return v_m[req.body.locale].format.number
    })
       .bail()
       .custom((value, {req}) => {
         if (relativeBearingBarHeight(req.body.gratingType, req.body.crossBarPitch).includes(Number(value))) return true
         else return Promise.reject(validationMessages[req.body.locale].bearingBarHeight_not_ok)
       }),

    body('clearSpan')
       .notEmpty().withMessage((value, {req}) => {
      return validationMessages[req.body.locale].clearSpan
    })
       .bail()
       .isNumeric().withMessage((value, {req}) => {
      return v_m[req.body.locale].format.number
    }),


    //////////////////////////// cross bar height and thickness
    body('crossBarThickness')
       .custom((value, {req}) => {
         if (req.body.gratingType === 'pressured' && !value) return Promise.reject(validationMessages[req.body.locale].crossBarThickness)
         else return true
       })
       .bail()
       .if((value, {req}) => req.body.gratingType === 'pressured')
       .isNumeric().withMessage((value, {req}) => {
      return v_m[req.body.locale].format.number
    }),

    body('crossBarHeight')
       .custom((value, {req}) => {
         if (req.body.gratingType === 'pressured' && !value) return Promise.reject(validationMessages[req.body.locale].crossBarHeight)
         else return true
       })
       .bail()
       .if((value, {req}) => req.body.gratingType === 'pressured')
       .isNumeric().withMessage((value, {req}) => {
      return v_m[req.body.locale].format.number
    })


  ],
  (req, res) => {
    const errors = validationResult(req)
    if (!errors.isEmpty()) return res.status(422).json({validation: errors.mapped()})

    let method = req.body.method
    let gratingType = req.body.gratingType
    let loadType = req.body.loadType
    let vehicleClass = req.body.vehicleClass

    let bearingBarHeight = req.body.bearingBarHeight
    let crossBarHeight = req.body.crossBarHeight
    let bearingBarThickness = req.body.bearingBarThickness
    let crossBarThickness = req.body.crossBarThickness
    let bearingBarPitch = req.body.bearingBarPitch
    let crossBarPitch = req.body.crossBarPitch
    let clearSpan = req.body.clearSpan
    let locale = req.body.locale


    ///////// classified vehicles
    const vehiclesClasses = {
      'class1': {
        distributedLoad: 6
      },
      'class2': {
        pointedLoad: 10,
        c4: 200,
        d4: 200
      },
      'class3': {
        pointedLoad: 30,
        c4: 200,
        d4: 400
      },
      'class4': {
        pointedLoad: 90,
        c4: 250,
        d4: 600
      },
      'FL1': {
        pointedLoad: 26,
        c4: 130,
        d4: 130
      },
      'FL2': {
        pointedLoad: 40,
        c4: 150,
        d4: 175
      },
      'FL3': {
        pointedLoad: 63,
        c4: 200,
        d4: 200
      },
      'FL4': {
        pointedLoad: 90,
        c4: 200,
        d4: 300
      },
      'FL5': {
        pointedLoad: 140,
        c4: 200,
        d4: 375
      },
      'FL6': {
        pointedLoad: 170,
        c4: 200,
        d4: 450
      },
    }

    ///////// grating weight
    const gratingLength = 1000
    const gratingWidth = 1000
    const frameThickness = 5
    const forgeCrossBarThickness = 6

    ///////// weight formula
    function forgeWeight() {
      // formula variables
      const B2 = Number(gratingLength)
      const B3 = Number(gratingWidth)
      const B4 = Number(bearingBarHeight)
      const B5 = Number(bearingBarThickness)
      const B6 = Number(forgeCrossBarThickness)
      const B7 = Number(bearingBarPitch)
      const B8 = Number(crossBarPitch)
      const B9 = Number(frameThickness)
      //
      const E2 = B2 - 2 * B9
      const E3 = B3
      const E4 = B2 - 2 * B9
      const E5 = B3
      //
      const H2 = 0
      const H3 = 2
      const H4 = E5 / B7 + 1
      const H5 = E4 / B8 - 1
      const H6 = E4 * B4 * B5 / 1000000 * 7.85 * H4
      const H7 = (E5 / 1000) * B6 * B6 * 7.85 / 1000 * H5
      const H8 = E2 * B9 * B4 / 1000000 * H2 * 7.85 + E3 * B4 * B9 / 1000000 * 7.85 * H3
      const H9 = (1750 * (25.25 / (B4 * B5)))

      //
      const E6 = H6 + H7 + H8
      //
      const K2 = E2 * (2 * (B4 + B5)) * H2 / 1000000
      const K3 = E3 * (2 * (B4 + B5)) * H3 / 1000000
      const K4 = E4 * (2 * (B4 + B5)) * H4 / 1000000
      const K5 = E5 * B6 * B6 * H5 / 1000000
      const K6 = K2 + K3 + K4 + K5
      const K7 = 80
      const K8 = K6 * K7 / 1000000 * 7140
      const K9 = K8 / E6 * 100
      //
      const E7 = K9 / 100 * E6
      const E8 = E6 + E7
      //
      const H10 = E8 / ((B2 * B3) / 1000000)


      // ///////// debug variables
      // // B
      // console.log('************ B Column ************')
      // console.log('B2 = ', B2)
      // console.log('B3 = ', B3)
      // console.log('B4 = ', B4)
      // console.log('B5 = ', B5)
      // console.log('B6 = ', B6)
      // console.log('B7 = ', B7)
      // console.log('B8 = ', B8)
      // console.log('B9 = ', B9)
      // // E
      // console.log('************ E Column ************')
      // console.log('E2 = ', E2)
      // console.log('E3 = ', E3)
      // console.log('E4 = ', E4)
      // console.log('E5 = ', E5)
      // console.log('E6 = ', E6)
      // console.log('E7 = ', E7)
      // console.log('E8 = ', E8)
      // // H
      // console.log('************ H Column ************')
      // console.log('H2 = ', H2)
      // console.log('H3 = ', H3)
      // console.log('H4 = ', H4)
      // console.log('H5 = ', H5)
      // console.log('H6 = ', H6)
      // console.log('H7 = ', H7)
      // console.log('H8 = ', H8)
      // console.log('H9 = ', H9)
      // console.log('H10 = ', H10)
      // // K
      // console.log('************ K Column ************')
      // console.log('K2 = ', K2)
      // console.log('K3 = ', K3)
      // console.log('K4 = ', K4)
      // console.log('K5 = ', K5)
      // console.log('K6 = ', K6)
      // console.log('K7 = ', K7)
      // console.log('K8 = ', K8)
      // console.log('K9 = ', K9)


      return {
        normal: Number(E6.toFixed(2)),
        galvanized: Number(E8.toFixed(2))
      }
    }

    function pressuredWeight() {
      // formula variables
      const B15 = Number(gratingLength)
      const B16 = Number(gratingWidth)
      const B17 = Number(bearingBarHeight)
      const B18 = Number(bearingBarThickness)
      const B19 = Number(crossBarHeight)
      const B20 = Number(crossBarThickness)
      const B21 = Number(bearingBarPitch)
      const B22 = Number(crossBarPitch)
      const B23 = Number(frameThickness)
      //
      const E15 = B15 - 2
      const E16 = B16 - 2 * B23 - 2
      const E17 = B15 - 2 * B23 - 2
      const E18 = B16 - 2 * B23 - 2
      //
      const H17 = E18 / B21 - 1
      const H18 = E17 / B22 - 1
      const H20 = E18 * B19 * B20 / 1000000 * 7.85 * H18
      //
      const H15 = 2
      const H16 = 2
      const H19 = E17 * B17 * B18 / 1000000 * 7.85 * H17
      const H21 = E15 * B23 * B17 / 1000000 * H15 * 7.85 + E16 * B17 * B23 / 1000000 * 7.85 * H16
      const H22 = H19 + H21
      //
      const E19 = H19 + H20 + H21 - ((H17 - 1) * (H18 - 1) * B18 * B19 * B20) * 7.85 / 1000000
      //
      const H23 = (H22 - E19) * 100 / E19
      //
      const K15 = E15 * (2 * (B17 + B18)) * H15 / 1000000
      const K16 = E16 * (2 * (B17 + B18)) * H16 / 1000000
      const K17 = E17 * (2 * (B17 + B18)) * H17 / 1000000
      const K18 = E18 * (2 * (B19 + B20)) * H18 / 1000000
      const K19 = K15 + K16 + K17 + K18
      const K20 = 80
      const K21 = K19 * K20 / 1000000 * 7140
      const K22 = K21 / E19 * 100
      //
      const E20 = K22 / 100 * E19
      // const E21=E19+E20-E22
      const E21 = E19 + E20
      const L25 = B15
      const L26 = B16
      //
      const K25 = L25 - 4 - 2 * B23 - B20
      const K26 = L26 - 4 - 2 * B23 - B18
      //

      return {
        normal: Number(E19.toFixed(2)),
        galvanized: Number(E21.toFixed(2))
      }
    }

    ///////// pointed load
    function pointedLoad() {
      // static variables
      const forge = gratingType === 'forge'
      const custom = method === 'custom'

      // computing m | c4 | d4 | pointedLoadValue
      function m_pressured(bearingBarHeight, crossBarPitch) {
        const CBPitch = Number(crossBarPitch)
        const BBHeight = Number(bearingBarHeight)

        if (BBHeight === 20) {
          if (CBPitch === 11) return 4.00
          if (CBPitch === 22) return 4.00
          if (CBPitch === 33) return 3.33
          if (CBPitch === 44) return 2.50
          if (CBPitch === 50) return 2.22
          if (CBPitch === 55) return 2.00
          if (CBPitch === 66) return 1.68
          if (CBPitch === 77) return 1.43
          if (CBPitch === 88) return 1.25
          if (CBPitch === 100) return 1.11
        } else if (BBHeight === 25) {
          if (CBPitch === 11) return 3.85
          if (CBPitch === 22) return 3.85
          if (CBPitch === 33) return 3.25
          if (CBPitch === 44) return 2.45
          if (CBPitch === 50) return 2.17
          if (CBPitch === 55) return 1.95
          if (CBPitch === 66) return 1.62
          if (CBPitch === 77) return 1.40
          if (CBPitch === 88) return 1.21
          if (CBPitch === 100) return 1.08
        } else if (BBHeight === 30) {
          if (CBPitch === 11) return 3.80
          if (CBPitch === 22) return 3.77
          if (CBPitch === 33) return 3.17
          if (CBPitch === 44) return 2.40
          if (CBPitch === 50) return 2.15
          if (CBPitch === 55) return 1.90
          if (CBPitch === 66) return 1.58
          if (CBPitch === 77) return 1.35
          if (CBPitch === 88) return 1.19
          if (CBPitch === 100) return 1.06
        } else if (BBHeight === 35) {
          if (CBPitch === 11) return 3.75
          if (CBPitch === 22) return 3.75
          if (CBPitch === 33) return 3.08
          if (CBPitch === 44) return 2.32
          if (CBPitch === 50) return 2.05
          if (CBPitch === 55) return 1.86
          if (CBPitch === 66) return 1.54
          if (CBPitch === 77) return 1.33
          if (CBPitch === 88) return 1.17
          if (CBPitch === 100) return 1.02
        } else if (BBHeight === 40) {
          if (CBPitch === 11) return 3.70
          if (CBPitch === 22) return 3.65
          if (CBPitch === 33) return 3.00
          if (CBPitch === 44) return 2.25
          if (CBPitch === 50) return 2.00
          if (CBPitch === 55) return 1.80
          if (CBPitch === 66) return 1.52
          if (CBPitch === 77) return 1.28
          if (CBPitch === 88) return 1.12
          if (CBPitch === 100) return 1.01
        } else if (BBHeight === 45) {
          if (CBPitch === 11) return 3.65
          if (CBPitch === 22) return 3.50
          if (CBPitch === 33) return 2.92
          if (CBPitch === 44) return 2.18
          if (CBPitch === 50) return 1.95
          if (CBPitch === 55) return 1.75
          if (CBPitch === 66) return 1.46
          if (CBPitch === 77) return 1.25
          if (CBPitch === 88) return 1.09
          if (CBPitch === 100) return 0.97
        } else if (BBHeight === 50) {
          if (CBPitch === 11) return 3.45
          if (CBPitch === 22) return 3.41
          if (CBPitch === 33) return 2.83
          if (CBPitch === 44) return 2.10
          if (CBPitch === 50) return 1.88
          if (CBPitch === 55) return 1.69
          if (CBPitch === 66) return 1.42
          if (CBPitch === 77) return 1.22
          if (CBPitch === 88) return 1.06
          if (CBPitch === 100) return 0.94
        } else if (BBHeight === 55) {
          if (CBPitch === 11) return 3.28
          if (CBPitch === 22) return 3.26
          if (CBPitch === 33) return 2.75
          if (CBPitch === 44) return 2.08
          if (CBPitch === 50) return 1.84
          if (CBPitch === 55) return 1.66
          if (CBPitch === 66) return 1.39
          if (CBPitch === 77) return 1.18
          if (CBPitch === 88) return 1.04
          if (CBPitch === 100) return 0.92
        } else if (BBHeight === 60) {
          if (CBPitch === 11) return 3.20
          if (CBPitch === 22) return 3.18
          if (CBPitch === 33) return 2.67
          if (CBPitch === 44) return 1.98
          if (CBPitch === 50) return 1.76
          if (CBPitch === 55) return 1.59
          if (CBPitch === 66) return 1.35
          if (CBPitch === 77) return 1.14
          if (CBPitch === 88) return 0.99
          if (CBPitch === 100) return 0.89
        } else if (BBHeight === 65) {
          if (CBPitch === 33) return 2.58
          if (CBPitch === 44) return 1.93
          if (CBPitch === 50) return 1.71
          if (CBPitch === 66) return 1.30
          if (CBPitch === 100) return 0.86
        } else if (BBHeight === 70) {
          if (CBPitch === 33) return 2.50
          if (CBPitch === 44) return 1.88
          if (CBPitch === 50) return 1.66
          if (CBPitch === 66) return 1.25
          if (CBPitch === 100) return 0.83
        } else if (BBHeight === 75) {
          if (CBPitch === 33) return 2.42
          if (CBPitch === 44) return 1.82
          if (CBPitch === 50) return 1.62
          if (CBPitch === 66) return 1.20
          if (CBPitch === 100) return 0.81
        } else if (BBHeight === 80) {
          if (CBPitch === 33) return 2.33
          if (CBPitch === 44) return 1.75
          if (CBPitch === 50) return 1.58
          if (CBPitch === 66) return 1.15
          if (CBPitch === 100) return 0.78
        } else if (BBHeight === 85) {
          if (CBPitch === 33) return 2.25
          if (CBPitch === 44) return 1.71
          if (CBPitch === 50) return 1.52
          if (CBPitch === 66) return 1.13
          if (CBPitch === 100) return 0.75
        } else if (BBHeight === 90) {
          if (CBPitch === 33) return 2.17
          if (CBPitch === 44) return 1.67
          if (CBPitch === 50) return 1.45
          if (CBPitch === 66) return 1.11
          if (CBPitch === 100) return 0.72
        } else if (BBHeight === 95) {
          if (CBPitch === 33) return 2.08
          if (CBPitch === 44) return 1.59
          if (CBPitch === 50) return 1.39
          if (CBPitch === 66) return 1.05
          if (CBPitch === 100) return 0.69
        } else if (BBHeight === 100) {
          if (CBPitch === 33) return 2.00
          if (CBPitch === 44) return 1.50
          if (CBPitch === 50) return 1.33
          if (CBPitch === 66) return 0.99
          if (CBPitch === 100) return 0.66
        }
      }

      function m_forge(bearingBarHeight, crossBarPitch) {
        const CBPitch = Number(crossBarPitch)
        const BBHeight = Number(bearingBarHeight)

        if (BBHeight === 20) {
          if (CBPitch === 38) return 2.25
          if (CBPitch === 50) return 1.35
          if (CBPitch === 76) return 0.81
          if (CBPitch === 100) return 0.52
        } else if (BBHeight === 25) {
          if (CBPitch === 38) return 2.19
          if (CBPitch === 50) return 1.28
          if (CBPitch === 76) return 0.77
          if (CBPitch === 100) return 0.52
        } else if (BBHeight === 30) {
          if (CBPitch === 38) return 2.13
          if (CBPitch === 50) return 1.25
          if (CBPitch === 76) return 0.75
          if (CBPitch === 100) return 0.48
        } else if (BBHeight === 35) {
          if (CBPitch === 38) return 2.06
          if (CBPitch === 50) return 1.20
          if (CBPitch === 76) return 0.71
          if (CBPitch === 100) return 0.47
        } else if (BBHeight === 40) {
          if (CBPitch === 38) return 2.00
          if (CBPitch === 50) return 1.17
          if (CBPitch === 76) return 0.67
          if (CBPitch === 100) return 0.45
        } else if (BBHeight === 45) {
          if (CBPitch === 38) return 1.94
          if (CBPitch === 50) return 1.11
          if (CBPitch === 76) return 0.65
          if (CBPitch === 100) return 0.43
        } else if (BBHeight === 50) {
          if (CBPitch === 38) return 1.88
          if (CBPitch === 50) return 1.05
          if (CBPitch === 76) return 0.62
          if (CBPitch === 100) return 0.40
        } else if (BBHeight === 55) {
          if (CBPitch === 38) return 1.81
          if (CBPitch === 50) return 1.03
          if (CBPitch === 76) return 0.61
          if (CBPitch === 100) return 0.38
        } else if (BBHeight === 60) {
          if (CBPitch === 38) return 1.75
          if (CBPitch === 50) return 1.00
          if (CBPitch === 76) return 0.59
          if (CBPitch === 100) return 0.36
        } else if (BBHeight === 65) {
          if (CBPitch === 38) return 1.69
        } else if (BBHeight === 70) {
          if (CBPitch === 38) return 1.63
        } else if (BBHeight === 75) {
          if (CBPitch === 38) return 1.56
        } else if (BBHeight === 80) {
          if (CBPitch === 38) return 1.50
        }
      }

      let m = () => {
        if (forge) return m_forge(bearingBarHeight, crossBarPitch)
        else return m_pressured(bearingBarHeight, crossBarPitch)
      }

      const c4 = () => {
        if (custom) return 200
        else return vehiclesClasses[vehicleClass].c4
      }
      const d4 = () => {
        if (custom) return 200
        else return vehiclesClasses[vehicleClass].d4
      }
      const pointedLoadValue = () => {
        if (custom) return req.body.pointedLoadValue
        else return vehiclesClasses[vehicleClass].pointedLoad
      }
      /////////////////////////////////////////////////////////////// computed variables
      const MaxM = (((pointedLoadValue() * 1000) * (clearSpan - (d4() / 2))) / 4) * 1.5
      const n = (c4() / bearingBarPitch) + m()
      const W = () => {
        const temp = (((bearingBarThickness * Math.pow(bearingBarHeight, 2)) / 6) * n)
        return forge ? temp : (temp * 0.9)
      }
      const sigma = MaxM / W()
      const L = () => {
        const temp = (((bearingBarThickness * (Math.pow(bearingBarHeight, 3))) / 12) * n)
        return forge ? temp : (temp * 0.9)
      }
      const D = ((pointedLoadValue() * 1000) / (384 * 210000 * L())) * ((8 * Math.pow(clearSpan, 3)) - (4 * clearSpan * Math.pow(d4(), 2)) + (Math.pow(d4(), 3)))

      // console.log('m =' + m())
      // console.log('c4 =' + c4())
      // console.log('d4 =' + d4())
      // console.log('pointedLoadValue =' + pointedLoadValue())
      // console.log('MaxM =' + MaxM)
      // console.log('n =' + n)
      // console.log('W =' + W())
      // console.log('sigma =' + sigma)
      // console.log('L =' + L())
      // console.log('D =' + D)

      //////////////////////////////////////////////////////////////// calculate result
      const result = {
        sigma: null,
        sigmaStatus: null,
        deflection: null,
        deflectionStatus: null,
        gratingWeight: forge ? forgeWeight() : pressuredWeight()
      }
      if (sigma < 235) {
        result.sigma = validationMessages[locale].sigma_ok
        result.sigmaStatus = true
      } else {
        result.sigma = validationMessages[locale].sigma_out_of_range
        result.sigmaStatus = false
      }

      if (D < (clearSpan / 200)) {
        result.deflection = validationMessages[locale].deflection_ok
        result.deflectionStatus = true
      } else {
        result.deflection = validationMessages[locale].deflection_out_of_range
        result.deflectionStatus = false
      }
      return result
    }

    ///////// distributed load
    function distributedLoad() {
      // static variables
      const forge = gratingType === 'forge'
      const custom = method === 'custom'
      // computing distributedLoadValue
      const distributedLoadValue = () => {
        if (custom) return req.body.distributedLoadValue
        else return vehiclesClasses[vehicleClass].distributedLoad
      }
      ////////////////////////////////////////////////////////////////// computed variables
      const MaxM = (((distributedLoadValue() * 10) * bearingBarPitch * Math.pow(clearSpan, 2)) / 80000) * 1.5
      const W = () => {
        const temp = (bearingBarThickness * Math.pow(bearingBarHeight, 2)) / 6
        return forge ? temp : (temp * 0.9)
      }
      const sigma = MaxM / W()
      const L = () => {
        const temp = (bearingBarThickness * Math.pow(bearingBarHeight, 3)) / 12
        return forge ? temp : (temp * 0.9)
      }
      const D = (5 * distributedLoadValue() * bearingBarPitch * Math.pow(clearSpan, 4)) / (384 * 21000 * L() * Math.pow(10, 4))
      ////////////////////////////////////////////////////////////////// calculate result
      const result = {
        sigma: null,
        sigmaStatus: null,
        deflection: null,
        deflectionStatus: null,
        gratingWeight: forge ? forgeWeight() : pressuredWeight()
      }
      if (sigma < 235) {
        result.sigma = validationMessages[locale].sigma_ok
        result.sigmaStatus = true
      } else {
        result.sigma = validationMessages[locale].sigma_out_of_range
        result.sigmaStatus = false
      }

      if (D < (clearSpan / 200)) {
        result.deflection = validationMessages[locale].deflection_ok
        result.deflectionStatus = true
      } else {
        result.deflection = validationMessages[locale].deflection_out_of_range
        result.deflectionStatus = false
      }
      return result
    }

    ////////////////////////////////////////////// calculate
    if (method === 'custom') {
      if (loadType === 'pointedLoad') return res.json(pointedLoad())
      else return res.json(distributedLoad())
    } else if (method === 'classified') {
      if (vehicleClass === 'class1') return res.json(distributedLoad())
      else return res.json(pointedLoad())
    } else return res.json({message: 'unsupported entry'})

  }
]


module.exports.getRelativeValues = [
  [
    body('gratingType')
       .notEmpty().withMessage((value, {req}) => {
      return validationMessages['fa'].gratingType
    })
       .bail()
       .custom((value, {req}) => {
         if (value === 'forge' || value === 'pressured') return true
         else Promise.reject(validationMessages['fa'].gratingType_not_supported)
       }),

    body('crossBarPitch')
       .notEmpty().withMessage((value, {req}) => {
      return validationMessages['fa'].crossBarPitch
    })
       .bail()
       .custom((value, {req}) => {
         if (req.body.gratingType === 'forge') {
           if (values.crossBarPitch_forge.includes(Number(value))) return true
           else return Promise.reject(validationMessages['fa'].crossBarPitch_not_ok)
         } else {
           if (values.crossBarPitch_pressured.includes(Number(value))) return true
           else return Promise.reject(validationMessages['fa'].crossBarPitch_not_ok)
         }
       })
  ],
  (req, res) => {
    const errors = validationResult(req)
    if (!errors.isEmpty()) return res.status(422).json(errors.mapped())
    return res.json(relativeBearingBarHeight(req.body.gratingType, req.body.crossBarPitch))
  }
]


module.exports.getValues = [
  (req, res) => {
    return res.json(values)
  }
]
