<?php

/**
 * @package     Joomla.Site
 * @subpackage  com_formea
 *
 * @copyright   Copyright (C) 2010-2025 Feseur Sdn Bhd. All rights reserved.
 * @license     GNU General Public License version 2 or later; see LICENSE.txt
 * @version     1.3.0
 */

namespace Joomla\Component\Formea\Site\Helper;

defined('_JEXEC') or die;

use Exception;
use Feseur\Library\FsrDate;
use Feseur\Library\FsrHelper;
use Feseur\Library\FsrResponse;
use Joomla\CMS\Application\ApplicationHelper;
use Joomla\CMS\Application\CMSApplicationInterface;
use Joomla\CMS\Date\Date;
use Joomla\CMS\Factory;
use Joomla\CMS\Log\Log;
use Joomla\Component\Formea\Site\Libraries\FormeaSubmission;
use Joomla\Filesystem\File;
use Joomla\CMS\Language\Associations;
use Joomla\CMS\Language\Language;
use Joomla\CMS\Language\Text;
use Joomla\CMS\Session\Session;
use Joomla\CMS\Uri\Uri;
use Joomla\CMS\WebAsset\WebAssetManager;
use Joomla\Component\Formea\Site\Libraries\FormeaForm;
use Joomla\Component\Formea\Site\Model\FormeaModel;
use Joomla\Database\DatabaseDriver;
use Joomla\Filesystem\Path;
use Joomla\Registry\Registry;
use Joomla\Session\SessionInterface;
use RuntimeException;

class FormeaGeneralHelper
{
  /**
   * Function to get all available languages
   *
   * @return array languages object list
   * @since 1.0.0
   */
  public static function getLanguages($byKey = false)
  {
    $container = Factory::getContainer();
    /** @var DatabaseDriver $db */
    $db    = $container->get('DatabaseDriver');
    $query = $db->getQuery(true);
    $query->select('lang_id, lang_code, title, sef')
      ->from('#__languages')
      // ->where('published = 1')
      ->order('lang_id ASC, ordering ASC');
    $db->setQuery($query);
    $results   = $db->loadObjectList();
    $languages = [];
    if (!empty($results)) {
      $totalResults = count($results);
      for ($i = 0; $i < $totalResults; $i++) {
        $langCodeUnderscore                = str_replace('-', '_', $results[$i]->lang_code);
        $results[$i]->lang_code_underscore = $langCodeUnderscore;
        if ($byKey) {
          $languages[$langCodeUnderscore] = $results[$i];
        } else {
          $languages[] = $results[$i];
        }
      }
    }


    return $languages;
  }

  public static function getCurrentVersion()
  {
    $ret  = 'n/a';
    $path = JPATH_ROOT . '/administrator/components/com_formea/formea.xml';
    if (is_file(Path::clean($path))) {
      $xml = simplexml_load_file($path);
      if (isset($xml->version)) {
        $ret = (string) $xml->version;
      }
    }

    return $ret;
  }

  public static function getFooterVersion()
  {
    $date              = new Date();
    $version           = self::getCurrentVersion();
    $reportBugsUrl     = FORMEA_DEV_LINK . '/forum/formea';
    $featureRequestUrl = FORMEA_DEV_LINK . '/forum/feature-requests';
    $con               = <<<HTML
<div class="d-block py-3 text-center text-muted fs-sm">Copyright 2010-{$date->format('Y')} Feseur Sdn Bhd. &mdash; Formea {$version} | <a href="$reportBugsUrl" target="_blank">Report Bugs</a> | <a target="_blank" href="$featureRequestUrl">Feature requests</a> </div>
HTML;

    return $con;
  }

  /**
   * Method to check if Formea System Plugin is enabled
   * @return bool
   *
   * @since 1.0.0
   */
  public static function checkSystemPlg()
  {
    $container = Factory::getContainer();
    /** @var DatabaseDriver $db */
    $db    = $container->get('DatabaseDriver');
    $query = $db->getQuery(true);
    $query->select(['extension_id', 'enabled', 'type']);
    $query->from($db->quoteName('#__extensions'));
    $query->where($db->quoteName('name') . ' = ' . $db->quote('PLG_SYSTEM_FORMEA'));
    $query->where($db->quoteName('type') . ' = ' . $db->quote('plugin'));
    $db->setQuery($query);
    $formeaSystemPlugin = $db->loadObject();
    $enabled            = false;
    if (!empty($formeaSystemPlugin)) {
      $enabled = (int) $formeaSystemPlugin->enabled > 0;
    }

    return $enabled;
  }

  /**
   * Reformat array based on key index
   *
   * @param   array   $arr
   * @param   string  $key
   *
   * @return array  [[$key=>items[]]]
   *
   * @since 1.0.0
   */
  public static function formatKeyArray(array $arr, string $key = 'id')
  {
    $ret = [];
    if (!empty($arr)) {
      $totalArr = count($arr);
      for ($i = 0; $i < $totalArr; $i++) {
        if (is_object($arr[$i])) {
          if (!isset($arr[$i]->{$key})) {
            break;
          } else {
            $ret[$arr[$i]->{$key}] = $arr[$i];
          }
        } else {
          if (!isset($arr[$i][$key])) {
            break;
          } else {
            $ret[$arr[$i][$key]] = $arr[$i];
          }
        }
      }
    }

    return $ret;
  }

  public static function getTranslatableValue($array = [], $keys = [], $langTag = '')
  {
    $ret = [];
    //$totalArray = count($array);
    if (empty($langTag)) {
      $app     = Factory::getApplication();
      $langTag = $app->getLanguage()->getTag();
    }
    $langTagUnderscore = str_replace('-', '_', $langTag);
    if (!empty($array)) {
      if (isset($array[$langTagUnderscore])) {
        $totalKey = count($keys);
        for ($i = 0; $i < $totalKey; $i++) {
          if (isset($array[$langTagUnderscore][$keys[$i]])) {
            $ret[$keys[$i]] = $array[$langTagUnderscore][$keys[$i]];
          }
        }
      }
    }

    return $ret;
  }

  /**
   * Get blank object for element label setting
   *
   * @param $langTagUnderscore
   * @param $langTitle
   *
   * @return object
   *
   * @since 1.0.0
   */
  public static function getBlankLabelSetting($langTagUnderscore, $langTitle, $elementDetails = [], $previews = [], $previewBares = [])
  {
    $ret = (object) [
      'lang_code'       => $langTagUnderscore,
      'lang_title'      => $langTitle,
      'setting'         => (object) [
        'show_label'   => true,
        'position'     => 'TOP',
        'label_column' => 3,
        'align'        => 'LEFT'
      ],
      'preview'         => '',
      'previewSafe'     => '',
      'previewBare'     => '',
      'previewBareSafe' => '',
      'caption'         => '',
      'altCaption'      => '',
      'description'     => '',
      'helper_align'    => 'LEFT',
    ];
    if (!empty($previews)) {
      $preview = '';
      if (isset($previews[$langTagUnderscore])) {
        $preview = $previews[$langTagUnderscore];
      } else {
        $reset   = array_values($previews);
        $preview = $reset[0];
      }
      if (!empty($preview)) {
        $ret->preview = $preview;
      }
    }

    if (!empty($previewBares)) {
      $previewBare = '';
      if (isset($previewBares[$langTagUnderscore])) {
        $previewBare = $previewBares[$langTagUnderscore];
      } else {
        $resetBare   = array_values($previewBares);
        $previewBare = $resetBare[0];
      }
      if (!empty($previewBare)) {
        $ret->previewBare = $previewBare;
      }
    }

    if (!empty($elementDetails)) {
      $caption     = self::getTranslatableValue($elementDetails, ['caption'], $langTagUnderscore);
      $description = self::getTranslatableValue($elementDetails, ['description'], $langTagUnderscore);
      if (!empty($caption)) {
        if (isset($caption['caption'])) {
          $ret->caption = $caption['caption'];
        }
      }
      if (!empty($description)) {
        if (isset($description['description'])) {
          $ret->description = $description['description'];
        }
      }
    }

    return $ret;
  }

  public static function prepareLangData($byKey = false)
  {
    $ret               = [];
    $app               = Factory::getApplication();
    $langTag           = $app->getLanguage()->getTag();
    $langTagUnderscore = str_replace('-', '_', $langTag);
    $languages         = self::getLanguages();
    $totalLanguages    = count($languages);
    for ($i = 0; $i < $totalLanguages; $i++) {
      if ($languages[$i]->lang_code === $langTag) {
        if ($byKey) {
          $ret[$langTagUnderscore] = null;
        } else {
          $ret[] = $langTagUnderscore;
        }

        break;
      }
    }
    if (Associations::isEnabled()) {
      for ($i = 0; $i < $totalLanguages; $i++) {
        if ($languages[$i]->lang_code !== $langTag) {
          $_langTagUnderscore = str_replace('-', '_', $languages[$i]->lang_code);
          if ($byKey) {
            $ret[$_langTagUnderscore] = null;
          } else {
            $ret[] = $_langTagUnderscore;
          }
        }
      }
    }

    return $ret;
  }

  public static function prepareLangDataVerbose($byKey = false)
  {
    $ret               = [];
    $app               = Factory::getApplication();
    $langTag           = $app->getLanguage()->getTag();
    $langTagUnderscore = str_replace('-', '_', $langTag);
    $languages         = self::getLanguages();
    $totalLanguages    = count($languages);
    for ($i = 0; $i < $totalLanguages; $i++) {
      if ($languages[$i]->lang_code === $langTag) {
        if ($byKey) {
          $ret[$langTagUnderscore] = [
            'lang_code'  => $langTagUnderscore,
            'lang_title' => $languages[$i]->title
          ];
        } else {
          $ret[] = [
            'lang_code'  => $langTagUnderscore,
            'lang_title' => $languages[$i]->title,
          ];
        }

        break;
      }
    }
    if (Associations::isEnabled()) {
      for ($i = 0; $i < $totalLanguages; $i++) {
        if ($languages[$i]->lang_code !== $langTag) {
          $_langTagUnderscore = str_replace('-', '_', $languages[$i]->lang_code);
          if ($byKey) {
            $ret[$_langTagUnderscore] = [
              'lang_code'  => $_langTagUnderscore,
              'lang_title' => $languages[$i]->title
            ];
          } else {
            $ret[] = [
              'lang_code'  => $_langTagUnderscore,
              'lang_title' => $languages[$i]->title,
            ];
          }
        }
      }
    }

    return $ret;
  }

  public static function findElementId($data)
  {
    $container = Factory::getContainer();
    /** @var DatabaseDriver $db */
    $db    = $container->get('DatabaseDriver');
    $query = $db->getQuery(true);
    $query->select('id');
    $query->from($db->quoteName('#__formea_elements'));
    $query->where($db->quoteName('type') . ' = ' . $db->quote($data['type']));
    $query->where($db->quoteName('alias') . ' = ' . $db->quote($data['alias']));
    $db->setQuery($query);

    return (int) $db->loadResult();
  }

  public static function getDefaultLangVal($data, $keyCheck, $verbose = false, $preferred_lang_code = '')
  {
    $ret = [];
    if (!$verbose) {
      foreach ($data as $lang_code => $datum) {
        if (empty($ret) && !empty($preferred_lang_code)) {
          $preferred_lang_code = str_replace('-', '_', $preferred_lang_code);
          $tlang_code          = str_replace('-', '_', $lang_code);
          if (strtoupper($preferred_lang_code) === strtoupper($tlang_code)) {
            if (isset($datum[$keyCheck])) {
              if (!empty($datum[$keyCheck])) {
                $ret = $datum;
                break;
              }
            }
          }
        }
        if (empty($ret)) {
          if (isset($datum[$keyCheck])) {
            if (!empty($datum[$keyCheck])) {
              $ret = $datum;
              break;
            }
          }
        }
      }
    }

    return $ret;
  }

  public static function getDefaultLangValField(array $field, array $data, string $preferred_lang_code = '')
  {
    $ret        = [];
    $totalField = count($field);
    for ($i = 0; $i < $totalField; $i++) {
      if (empty($ret)) {
        $ret = self::getDefaultLangVal($data, $field[$i], false, $preferred_lang_code);
      } else {
        break;
      }
    }

    return $ret;
  }

  /**
   * Global placeholder for content/snippet
   *
   * @param $submission_url
   *
   * @return array
   *
   * @throws Exception
   * @since 1.0.0
   */
  public static function getGlobalPlaceholders($submission_url = '')
  {
    $app         = Factory::getApplication();
    $config      = $app->getConfig();
    $admin_email = $config->get('mailfrom');
    $fromname    = $config->get('fromname');
    $replyto     = $config->get('replyto');
    $replytoname = $config->get('replytoname');
    if (empty($replyto)) {
      $replyto = $admin_email;
    }
    if (empty($replytoname)) {
      $replytoname = $fromname;
    }

    return [
      'GLOBAL_FROM_EMAIL'      => $admin_email,
      'GLOBAL_FROM_EMAIL_NAME' => $fromname,
      'GLOBAL_TO_EMAIL'        => $replyto,
      'GLOBAL_TO_EMAIL_NAME'   => $replytoname,
      'GLOBAL_SITE_NAME'       => $config->get('sitename'),
      'ROOT_PATH'              => JPATH_ROOT,
      'SUBMISSION_URL'         => $submission_url,
      'SITE_URL'               => Uri::root(),
    ];
  }

  public static function mapExistingLabelSetting($defaultLabelSettings, $existingLabelSettings)
  {
    $totalDefaultLabelSettings  = count($defaultLabelSettings);
    $totalExistingLabelSettings = count($existingLabelSettings);
    for ($i = 0; $i < $totalExistingLabelSettings; $i++) {
      for ($j = 0; $j < $totalDefaultLabelSettings; $j++) {
        if ($existingLabelSettings[$i]->lang_code === $defaultLabelSettings[$j]->lang_code) {
          $defaultLabelSettings[$j]->setting      = $existingLabelSettings[$i]->setting;
          $defaultLabelSettings[$j]->helper_align = $existingLabelSettings[$i]->helper_align;
        }
      }
    }

    return $defaultLabelSettings;
  }

  public static function searchByKeyRecursive($array, $key)
  {
    $results = [];
    foreach ($array as $item) {
      if (isset($item[$key])) {
        $results[] = $item[$key];
      } else {
        if (is_array($item)) {
          $subResults = self::searchByKeyRecursive($item, $key);
          $results    = array_merge($results, $subResults);
        }
      }
    }

    return $results;
  }

  public static function getGeneralElementSettings()
  {
    return [
      'containerClass'    => '',
      'paddingTopLeft'    => '',
      'paddingTop'        => '',
      'paddingBottom'     => '',
      'paddingLeft'       => '',
      'paddingRight'      => '',
      'borderTopWidth'    => '',
      'borderRightWidth'  => '',
      'borderBottomWidth' => '',
      'borderLeftWidth'   => '',
      'borderStyle'       => '',
      'borderColor'       => '',
      'radiusTopLeft'     => '',
      'radiusTopRight'    => '',
      'radiusBottomLeft'  => '',
      'radiusBottomRight' => '',
      'backgroundColor'   => '',
      'textColor'         => '',
    ];
  }

  public static function getStyleSheetParams()
  {
    return [
      'paddingTop'        => ['padding-top'],
      'paddingBottom'     => ['padding-bottom'],
      'paddingLeft'       => ['padding-left'],
      'paddingRight'      => ['padding-right'],
      'borderTopWidth'    => ['border-top-width'],
      'borderRightWidth'  => ['border-right-width'],
      'borderBottomWidth' => ['border-bottom-width'],
      'borderLeftWidth'   => ['border-left-width'],
      'borderStyle'       => ['border-style'],
      'borderColor'       => ['border-color'],
      'radiusTopLeft'     => ['border-top-left-radius'],
      'radiusTopRight'    => ['border-top-right-radius'],
      'radiusBottomLeft'  => ['border-bottom-left-radius'],
      'radiusBottomRight' => ['border-bottom-right-radius'],
      'backgroundColor'   => ['background-color'],
      'textColor'         => ['color'],
    ];
  }

  public static function getMultipleValueSettingParam()
  {
    return [
      'padding' => [
        'paddingTop',
        'paddingBottom',
        'paddingLeft',
        'paddingRight',
      ],
      'border'  => [
        'borderTopWidth',
        'borderRightWidth',
        'borderBottomWidth',
        'borderLeftWidth',
      ],
      'radius'  => [
        'radiusTopLeft',
        'radiusTopRight',
        'radiusBottomLeft',
        'radiusBottomRight',
      ]
    ];
  }

  /**
   * @param $state
   * @param $extension_type
   * @param $has_view
   *
   * @return array|mixed
   *
   * @since version
   */
  public static function getCoreExtensions($state = -1, $extension_type = [], $has_view = -1)
  {
    $container = Factory::getContainer();
    /** @var DatabaseDriver $db */
    $db    = $container->get('DatabaseDriver');
    $query = $db->getQuery(true);
    $query->select('*');
    $query->from($db->quoteName('#__formea_cores'));
    if ($state > -1) {
      $query->where($db->quoteName('state') . ' = ' . $db->quote($state));
    }
    if (!empty($extension_type)) {
      $whereCondition = [];
      foreach ($extension_type as $ext_type) {
        $whereCondition[] = $db->quoteName('extension_type') . ' = ' . $db->quote($ext_type);
      }
      $query->where(implode(' OR ', $whereCondition));
    }
    if ($has_view > -1) {
      $query->where($db->quoteName('has_view') . ' = ' . $db->quote($has_view));
    }
    $query->order('id ASC');
    $db->setQuery($query);

    return $db->loadObjectList();
  }

  public static function getFormeaExtensions($state = -1)
  {
    $container = Factory::getContainer();
    /** @var DatabaseDriver $db */
    $db          = $container->get('DatabaseDriver');
    $query       = $db->getQuery(true);
    $coreColumns = [
      'a.id AS extension_id',
      'a.name',
      'a.title',
      'a.author',
      'a.creation_date',
      'a.copyright',
      'a.license',
      'a.author_email',
      'a.author_url',
      'a.version',
      'a.description',
      'a.params',
      'a.state',
      'a.created_date',
      'a.modified_date',
      'a.modified_by',
      'a.created_by',
      '\'core\' AS extension_type',
    ];

    $query->select($coreColumns);
    $query->from($db->quoteName('#__formea_cores', 'a'));

    $elementColumns = [
      'b.id AS extension_id',
      'b.name',
      'b.title',
      'b.author',
      'b.creation_date',
      'b.copyright',
      'b.license',
      'b.author_email',
      'b.author_url',
      'b.version',
      'b.description',
      'b.params',
      'b.state',
      'b.created_date',
      'b.modified_date',
      'b.modified_by',
      'b.created_by',
      '\'element\' AS extension_type',
    ];
    $elementQuery   = $db->getQuery(true);
    $elementQuery->select($elementColumns);
    $elementQuery->from($db->quoteName('#__formea_eltypes', 'b'));

    $themeColumns = [
      'c.id AS extension_id',
      'c.name',
      'c.title',
      'c.author',
      'c.creation_date',
      'c.copyright',
      'c.license',
      'c.author_email',
      'c.author_url',
      'c.version',
      'c.description',
      'c.params',
      'c.state',
      'c.created_date',
      'c.modified_date',
      'c.modified_by',
      'c.created_by',
      '\'theme\' AS extension_type',
    ];
    $themeQuery   = $db->getQuery(true);
    $themeQuery->select($themeColumns);
    $themeQuery->from($db->quoteName('#__formea_themes', 'c'));

    $validationColumns = [
      'd.id AS extension_id',
      'd.name',
      'd.title',
      'd.author',
      'd.creation_date',
      'd.copyright',
      'd.license',
      'd.author_email',
      'd.author_url',
      'd.version',
      'd.description',
      'd.params',
      'd.state',
      'd.created_date',
      'd.modified_date',
      'd.modified_by',
      'd.created_by',
      '\'validation\' AS extension_type',
    ];
    $validationQuery   = $db->getQuery(true);
    $validationQuery->select($validationColumns);
    $validationQuery->from($db->quoteName('#__formea_validations', 'd'));

    $query->unionAll($elementQuery);
    $query->unionAll($themeQuery);
    $query->unionAll($validationQuery);
    if ($state > -1) {
      $query->where($db->quoteName('a.state') . ' = ' . $db->quote($state));
    }
    $db->setQuery($query);

    return $db->loadObjectList();
  }

  public static function getCoreExtension($id, $state = -1, $extension_type = -1, $has_view = -1)
  {
    $container = Factory::getContainer();
    /** @var DatabaseDriver $db */
    $db    = $container->get('DatabaseDriver');
    $query = $db->getQuery(true);
    $query->select('*');
    $query->from($db->quoteName('#__formea_cores'));
    $query->where($db->quoteName('id') . ' = ' . $db->quote($id));
    if ($state > -1) {
      $query->where($db->quoteName('state') . ' = ' . $db->quote($state));
    }
    if ($extension_type > -1) {
      $query->where($db->quoteName('extension_type') . ' = ' . $db->quote($extension_type));
    }
    if ($has_view > -1) {
      $query->where($db->quoteName('has_view') . ' = ' . $db->quote($has_view));
    }
    $db->setQuery($query);

    return $db->loadObject();
  }

  public static function getExtensionStyles($extension_id, $extension_type)
  {
    $container = Factory::getContainer();
    /** @var DatabaseDriver $db */
    $db    = $container->get('DatabaseDriver');
    $query = $db->getQuery(true);
    $query->select('*');
    $query->from($db->quoteName('#__formea_extension_styles'));
    $query->where($db->quoteName('extension_id') . ' = ' . $db->quote($extension_id));
    $query->where($db->quoteName('extension_type') . ' = ' . $db->quote($extension_type));
    $query->order('id ASC');
    $db->setQuery($query);
    $styles = $db->loadObjectList();
    if (!empty($styles)) {
      $totalStyles = count($styles);
      for ($i = 0; $i < $totalStyles; $i++) {
        if (!empty($styles[$i]->params)) {
          $styles[$i]->params = json_decode($styles[$i]->params);
        } else {
          $styles[$i]->params = [];
        }
      }
    }

    return $styles;
  }

  public static function getExtensionStyle($style_id)
  {
    $container = Factory::getContainer();
    /** @var DatabaseDriver $db */
    $db    = $container->get('DatabaseDriver');
    $query = $db->getQuery(true);
    $query->select('*');
    $query->from($db->quoteName('#__formea_extension_styles'));
    $query->where($db->quoteName('id') . ' = ' . $db->quote($style_id));
    $db->setQuery($query);
    $styles = $db->loadObject();
    if (!empty($styles)) {
      if (!empty($styles->params)) {
        $styles->params = json_decode($styles->params);
      } else {
        $styles->params = [];
      }
    }

    return $styles;
  }

  public static function getCssBorderStyles()
  {
    return [
      'dotted',
      'dashed',
      'solid',
      'double',
      'groove',
      'ridge',
      'inset',
      'outset',
      'none',
      'hidden',
    ];
  }

  public static function getFormLayoutColumnOptions()
  {
    return [
      ["columns" => [12], "text" => "1 Column", "gridText" => "12"],
      ["columns" => [6, 6], "text" => "2 Columns", "gridText" => "6,6"],
      ["columns" => [4, 4, 4], "text" => "3 Columns", "gridText" => "4,4,4"],
      ["columns" => [5, 7], "text" => "2 Columns", "gridText" => "5,7"],
      ["columns" => [7, 5], "text" => "2 Columns", "gridText" => "7,5"],
    ];
  }

  public static function getGutterOptions()
  {
    return [
      ['text' => Text::_('COM_FORMEA_DEFAULT'), 'val' => -1],
      ['text' => Text::_('COM_FORMEA_NONE'), 'val' => 0],
      ['text' => Text::_('COM_FORMEA_XSMALL'), 'val' => 1],
      ['text' => Text::_('COM_FORMEA_SMALL'), 'val' => 2],
      ['text' => Text::_('COM_FORMEA_MEDIUM'), 'val' => 3],
      ['text' => Text::_('COM_FORMEA_LARGE'), 'val' => 4],
      ['text' => Text::_('COM_FORMEA_XLARGE'), 'val' => 5],
    ];
  }

  public static function removeExtensionStyle($extension_id, $extension_type = 0)
  {
    $container = Factory::getContainer();
    /** @var DatabaseDriver $db */
    $db    = $container->get('DatabaseDriver');
    $query = $db->getQuery(true);
    // delete all custom keys for user 1001.
    $conditions = array(
      $db->quoteName('extension_id') . ' = ' . $extension_id,
      $db->quoteName('extension_type') . ' = ' . $extension_type
    );
    $query->delete($db->quoteName('#__formea_extension_styles'));
    $query->where($conditions);
    $db->setQuery($query);

    return $db->execute();
  }

  public static function loadFormeaLayout($layout, $data = array())
  {
    $app = Factory::getApplication();
    if (is_file(Path::clean($layout))) {
      $path = $layout;
    } else {
      throw new RuntimeException(Text::_('COM_FORMEA_TEMPLATE_DOES_NOT_EXISTS'));
    }

    // Start an output buffer.
    ob_start();
    extract($data);

    // Load the layout.
    include $path;

    // Get the layout contents.
    $output = ob_get_clean();

    return $output;
  }

  /**
   * @param   int   $form_id
   * @param   bool  $drawContent
   * @param   bool  $setAssets  whether to use webasset manager to disperse the assets
   *
   * @return FsrResponse
   *
   * @since 1.0.0
   */
  public static function renderForm($form_id, $drawContent = false, $setAssets = true)
  {
    $retObject   = new FsrResponse();
    $returnArray = [
      'content'           => '',
      'formObject'        => null,
      'formClass'         => null,
      'rendererExtension' => null,
      'assets'            => null,
      'submissionData'    => null,
    ];
    /** @var CMSApplicationInterface $app */
    $app = Factory::getApplication();
    $app->getLanguage()->load('com_formea', JPATH_SITE . '/components/com_formea');
    try {
      if ($form_id < 1) {
        throw new Exception(Text::_('COM_FORMEA_INVALID_FORM'));
      }
      $model = new FormeaModel();
      $_item = $model->getItem($form_id);
      if (empty($_item)) {
        throw new Exception(Text::_('COM_FORMEA_FORM_NOT_FOUND'));
      }


      $user   = $app->getIdentity();
      $groups = $user->getAuthorisedViewLevels();
      if (!in_array($_item->access_level, $groups)) {
        throw new Exception(Text::_('JERROR_ALERTNOAUTHOR'));
      }
      $dispatcher = $app->getDispatcher();
      $formClass  = new FormeaForm(['id' => $_item->id]);
      $item       = $formClass->getObject(1);


      $state       = $model->getState();
      $stateParams = $state->get('params');
      $itemparams  = $_item->params;

      $temp = clone $stateParams;
      $temp->merge($itemparams);
      $item->params         = $temp;
      $item->details        = $formClass->getDetails();
      $item->themes         = $formClass->getThemes();
      $item->elementLayouts = $formClass->getPages();

      $elementAssets = $formClass->getAllAssets();
      if (!empty($item->inline_css)) {
        $elementAssets->inlineStyles[] = $item->inline_css;
      }

      $returnArray['assets'] = $elementAssets;

      if ($setAssets) {
        /** @var WebAssetManager $wa */
        $wa       = $app->getDocument()->getWebAssetManager();
        $registry = $wa->getRegistry();
        $registry->addRegistryFile('/media/com_formea/joomla.asset.json');

        $csrf = Session::getFormToken();
        $formeaOption = [
          'oid' => $csrf,
          'base_url' => Uri::base()
        ];
        $wa->addInlineScript('var FormeaOption = ' . json_encode($formeaOption) . ';');

        $totalCssFiles = count($elementAssets->fileStyles);
        for ($i = 0; $i < $totalCssFiles; $i++) {
          $wa->useStyle($elementAssets->fileStyles[$i]);
        }

        $totalJsFiles = count($elementAssets->fileScripts);
        for ($i = 0; $i < $totalJsFiles; $i++) {
          $wa->useScript($elementAssets->fileScripts[$i]);
        }

        $totalInlineScripts = count($elementAssets->inlineScripts);
        for ($i = 0; $i < $totalInlineScripts; $i++) {
          $wa->addInlineScript($elementAssets->inlineScripts[$i]);
        }

        $totalInlineStyles = count($elementAssets->inlineStyles);
        for ($i = 0; $i < $totalInlineStyles; $i++) {
          $wa->addInlineStyle($elementAssets->inlineStyles[$i]);
        }
      }


      /** @var SessionInterface $session */
      $session       = Factory::getApplication()->getSession();
      $submittedData = $session->get('FORMEA_FORM_SUBMISSION_' . $item->id);

      if (!empty($submittedData)) {
        $returnArray['submissionData'] = $submittedData;
        $session->remove('FORMEA_FORM_SUBMISSION_' . $item->id);
      }
      $rendererExtension = null;
      $layoutPath        = '';
      if ($item->form_type > 0) {
        $renderer_id = $item->params->get('renderer_id', 0);
        if ($renderer_id > 0) {
          $rendererExtension = FormeaGeneralHelper::getCoreExtension($renderer_id, 1, 1);
          if (!empty($rendererExtension)) {
            $rendererDirectory = JPATH_ROOT . '/components/com_formea/plugins/core/' . $rendererExtension->name . '/';
            if (is_file(Path::clean($rendererDirectory . 'tmpl/module.php'))) {
              $layoutPath = $rendererDirectory . 'tmpl/module.php';
            }
          }
        }
      }

      $returnArray['formObject']        = $item;
      $returnArray['formClass']         = $formClass;
      $returnArray['rendererExtension'] = $rendererExtension;

      if ($drawContent) {
        if (empty($layoutPath)) {
          $layoutPath = JPATH_ROOT . '/components/com_formea/tmpl/formea/module.php';
        }

        $content = self::loadFormeaLayout($layoutPath, [
          'formClass'         => $formClass,
          'formObject'        => $item,
          'rendererExtension' => $returnArray['rendererExtension'],
          'submissionData'    => $returnArray['submissionData']
        ]);

        $returnArray['content'] = $content;
      }

      $retObject->setSuccess(true);
    } catch (Exception $e) {
      $retObject->setMsg($e->getMessage());
    }

    $retObject->setResult($returnArray);

    return $retObject;
  }

  /**
   * Method to load Formea extension language file
   *
   * @param   string    $extensionName
   * @param   string    $extensionFolder
   * @param   Language  $lang
   * @param   string    $langTag
   *
   *
   * @return void
   * @since 1.0.3
   */
  public static function loadExtensionLanguage($extensionName, $extensionFolder = 'element', $lang = null, string $langTag = 'en-GB')
  {
    $defaultLangTag = 'en-GB';
    try {
      if (empty($lang)) {
        $app  = Factory::getApplication();
        $lang = $app->getLanguage();
      }
      if (empty($langTag)) {
        $langTag = $lang->getTag();
      }

      $langPath = JPATH_ROOT . DIRECTORY_SEPARATOR . 'components' . DIRECTORY_SEPARATOR . 'com_formea' .
        DIRECTORY_SEPARATOR . 'plugins' . DIRECTORY_SEPARATOR . $extensionFolder . DIRECTORY_SEPARATOR . $extensionName;

      if (is_dir(Path::clean($langPath . DIRECTORY_SEPARATOR . 'language' . DIRECTORY_SEPARATOR . $langTag))) {
        $lang->load($extensionName, $langPath, $langTag);
      } else {
        if (is_dir(Path::clean($langPath . DIRECTORY_SEPARATOR . 'language' . DIRECTORY_SEPARATOR . $defaultLangTag))) {
          $lang->load($extensionName, $langPath, $defaultLangTag);
        }
      }
    } catch (Exception $e) {
    }
  }

  /**
   * Method to check submission for form submission redirect to URL that is not a Formea controller
   *
   * @return array
   * @since 1.1.3
   */
  public static function checkSubmission()
  {
    $ret                 = ['hasError' => false];
    $app                 = Factory::getApplication();
    $session             = $app->getSession();
    $formeaSubmittedData = $session->get('FORMEA_SUBMITTED_DATA');
    if (!empty($formeaSubmittedData)) {
      foreach ($formeaSubmittedData as $submission_id => $data) {
        $formeaSubmission = new FormeaSubmission($submission_id);
        $sendMail         = $formeaSubmission->sendMail($data);
        if (!$sendMail->success) {
          $ret['hasError'] = true;
        }
        unset($formeaSubmittedData[$submission_id]);
      }
      if (empty($formeaSubmittedData)) {
        $formeaSubmittedData = [];
      }
      $session->set('FORMEA_SUBMITTED_DATA', $formeaSubmittedData);
    }

    return $ret;
  }

  /**
   * Get all formea installable extensions and group it by type
   * @param int $state
   *
   *
   * @since 1.2.2
   */
  public static function getGroupedFormeaExtensions($state = -1, $keyByName = false)
  {
    $extensions = self::getFormeaExtensions($state);

    // Initialize each type as an array within the object
    $groupedExtensions = (object) [
      'eltypes'     => [],
      'validations' => [],
      'themes'      => [],
      'cores'        => []
    ];

    $totalExtensions = count($extensions);

    for ($i = 0; $i < $totalExtensions; $i++) {
      $extension = $extensions[$i];
      $name = $extension->name;

      // Group by extension type, either keyed by name or not
      switch ($extension->extension_type) {
        case 'core':
          if ($keyByName) {
            $groupedExtensions->cores[$name] = $extension;
          } else {
            $groupedExtensions->cores[] = $extension;
          }
          break;

        case 'theme':
          if ($keyByName) {
            $groupedExtensions->themes[$name] = $extension;
          } else {
            $groupedExtensions->themes[] = $extension;
          }
          break;

        case 'validation':
          if ($keyByName) {
            $groupedExtensions->validations[$name] = $extension;
          } else {
            $groupedExtensions->validations[] = $extension;
          }
          break;

        case 'element':
          if ($keyByName) {
            $groupedExtensions->eltypes[$name] = $extension;
          } else {
            $groupedExtensions->eltypes[] = $extension;
          }
          break;
      }
    }

    return $groupedExtensions;
  }

  /**
   * @param $columns
   * @param $ordering
   *
   * @return array|mixed
   *
   * @since 1.2.2
   */
  public static function getFormeaFormLists($columns = ['id', 'title', 'state'], $ordering = 'id DESC')
  {
    $container = Factory::getContainer();
    /** @var DatabaseDriver $db */
    $db = $container->get('DatabaseDriver');
    $query = $db->getQuery(true);
    $query->select($columns);
    $query->from($db->quoteName('#__formea_forms'));
    $query->order($ordering);
    $db->setQuery($query);
    return $db->loadObjectList();
  }

  /**
   * To merge multiple pages into only one
   * @param array $formPages
   *
   * @return array
   * @since 1.2.2
   */
  public static function mergeFormPages($formPages)
  {
    if (!empty($formPages)) {
      $formPage = new \stdClass();
      $formPage->id = $formPages[0]->id;
      $formPage->form_id = $formPages[0]->form_id;
      $formPage->title = $formPages[0]->title;
      $formPage->subtitle = $formPages[0]->subtitle;
      $formPage->icon = $formPages[0]->icon;
      $formPage->settings = $formPages[0]->settings;
      $formPage->layout = [];
      $formPage->styleSheet = $formPages[0]->styleSheet;
      $formPage->rows = [];
      $formPage->selected = true;
      foreach ($formPages as $page) {
        $formPage->layout = array_merge($formPage->layout, $page->layout);
        $formPage->rows = array_merge($formPage->rows, $page->rows);
      }

      $formPages = [];
      $formPages[] = $formPage;
    }
    return $formPages;
  }
}
