/****************************************************************************
**
** https://www.qxorm.com/
** Copyright (C) 2013 XDL Team (ic-east.com)
**
** This file is part of the QxOrm library
**
** This software is provided 'as-is', without any express or implied
** warranty. In no event will the authors be held liable for any
** damages arising from the use of this software
**
** Commercial Usage
** Licensees holding valid commercial QxOrm licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and XDL Team
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3.0 as published by the Free Software
** Foundation and appearing in the file 'license.gpl3.txt' included in the
** packaging of this file. Please review the following information to
** ensure the GNU General Public License version 3.0 requirements will be
** met : http://www.gnu.org/copyleft/gpl.html
**
** If you are unsure which license is appropriate for your use, or
** if you have questions regarding the use of this file, please contact :
** ic-east.com
**
****************************************************************************/

#include <QxPrecompiled.h>

#ifndef _QX_NO_JSON

#include <QxSerialize/QJson/QxSerializeQJson_QxSqlQuery.h>
#include <QxSerialize/QJson/QxSerializeQJson_std_tuple.h>
#include <QxSerialize/QJson/QxSerializeQJson_QHash.h>
#include <QxSerialize/QJson/QxSerializeQJson_QVector.h>
#include <QxSerialize/QJson/QxSerializeQJson_QFlags.h>
#include <QxSerialize/QJson/QxSerializeQJson_QStringList.h>
#include <QxSerialize/QJson/QxSerializeQJson_IxSqlElement.h>
#include <QxSerialize/QJson/QxSerializeQJson_QxCollection.h>

#include <QxMemLeak/mem_leak.h>

namespace qx
{
   namespace cvt
   {
      namespace detail
      {

         QJsonValue QxConvert_ToJson_Helper(const qx::QxSqlQuery &t, const QString &format)
         {
            QJsonObject obj;
            QJsonArray arr;
            QHash<QString, int> lstResultPosByKey;
            QVector<QVector<QVariant>> lstResultValues;
            qx::dao::detail::IxSqlElement::type_class eNoSqlType = qx::dao::detail::IxSqlElement::_no_type;

            if (t.m_pSqlResult)
            {
               lstResultPosByKey = t.m_pSqlResult->positionByKey;
               lstResultValues = t.m_pSqlResult->values;
            }

            obj.insert("query", qx::cvt::to_json(t.m_sQuery));
            obj.insert("list_values", qx::cvt::to_json(t.m_lstValue, format));
            obj.insert("sql_element_index", QJsonValue(t.m_iSqlElementIndex));
            obj.insert("parenthesis_count", QJsonValue(t.m_iParenthesisCount));
            obj.insert("distinct", QJsonValue(t.m_bDistinct));
            obj.insert("result_position_by_key", qx::cvt::to_json(lstResultPosByKey, format));
            obj.insert("result_values", qx::cvt::to_json(lstResultValues, format));
            obj.insert("response", QJsonValue(t.m_vResponse.toString()));
            obj.insert("type", QJsonValue(t.m_sType));
            obj.insert("list_join_query_user", qx::cvt::to_json(t.m_lstJoinQueryUser, format));
            obj.insert("list_join_query_resolve", qx::cvt::to_json(t.m_lstJoinQueryToResolve, format));

            if (!t.m_pSqlElementTemp)
            {
               obj.insert("sql_element_temp_type", QJsonValue(static_cast<int>(eNoSqlType)));
            }
            else
            {
               qx::dao::detail::IxSqlElement::type_class eTypeSqlElement = t.m_pSqlElementTemp->getTypeClass();
               obj.insert("sql_element_temp_type", QJsonValue(static_cast<int>(eTypeSqlElement)));
               obj.insert("sql_element_temp", qx::cvt::to_json((*t.m_pSqlElementTemp), format));
            }

            Q_FOREACH (qx::dao::detail::IxSqlElement_ptr pSqlElement, t.m_lstSqlElement)
            {
               QJsonObject item;
               if (!pSqlElement)
               {
                  item.insert("sql_element_type", QJsonValue(static_cast<int>(eNoSqlType)));
                  arr.append(QJsonValue(item));
                  continue;
               }
               qx::dao::detail::IxSqlElement::type_class eTypeSqlElement = pSqlElement->getTypeClass();
               item.insert("sql_element_type", QJsonValue(static_cast<int>(eTypeSqlElement)));
               item.insert("sql_element", qx::cvt::to_json((*pSqlElement), format));
               arr.append(QJsonValue(item));
            }
            obj.insert("sql_element_list", QJsonValue(arr));

            return QJsonValue(obj);
         }

         qx_bool QxConvert_FromJson_Helper(const QJsonValue &j, qx::QxSqlQuery &t, const QString &format)
         {
            t = qx::QxSqlQuery();
            if (!j.isObject())
            {
               return qx_bool(true);
            }
            QJsonObject obj = j.toObject();
            QHash<QString, int> lstResultPosByKey;
            QVector<QVector<QVariant>> lstResultValues;

            if (obj.contains("sql"))
            {
               QJsonValue jsonSql = obj.value("sql");
               if (jsonSql.isString())
               {
                  t.m_sQuery.clear();
                  t.m_sQuery << jsonSql.toString();
               }
            }
            else
            {
               qx::cvt::from_json(obj.value("query"), t.m_sQuery);
            }

            if (obj.contains("params"))
            {
               QJsonArray arrParams = obj.value("params").toArray();
               for (int i = 0; i < arrParams.count(); i++)
               {
                  QJsonValue objParam = arrParams.at(i);
                  if (!objParam.isObject())
                  {
                     continue;
                  }
                  QJsonObject jsonParam = objParam.toObject();
                  QSql::ParamType jsonParamType = QSql::In;
                  if (jsonParam.contains("type"))
                  {
                     QString paramType = jsonParam.value("type").toString();
                     if (paramType == "in")
                     {
                        jsonParamType = QSql::In;
                     }
                     else if (paramType == "out")
                     {
                        jsonParamType = QSql::Out;
                     }
                     else if (paramType == "in_out")
                     {
                        jsonParamType = QSql::InOut;
                     }
                     else if (paramType == "binary")
                     {
                        jsonParamType = QSql::Binary;
                     }
                  }
                  QString jsonParamKey;
                  QVariant jsonParamValue;
                  qx::cvt::from_json(jsonParam.value("key"), jsonParamKey);
                  qx::cvt::from_json(jsonParam.value("value"), jsonParamValue);
                  if (jsonParamKey.isEmpty())
                  {
                     t.bind(jsonParamValue, jsonParamType);
                  }
                  else
                  {
                     t.bind(jsonParamKey, jsonParamValue, jsonParamType);
                  }
               }
            }
            else
            {
               qx::cvt::from_json(obj.value("list_values"), t.m_lstValue, format);
            }

            t.m_iSqlElementIndex = qRound(obj.value("sql_element_index").toDouble());
            t.m_iParenthesisCount = qRound(obj.value("parenthesis_count").toDouble());
            t.m_bDistinct = obj.value("distinct").toBool();
            qx::cvt::from_json(obj.value("result_position_by_key"), lstResultPosByKey, format);
            qx::cvt::from_json(obj.value("result_values"), lstResultValues, format);
            t.m_vResponse = obj.value("response").toVariant();
            t.m_sType = obj.value("type").toString();
            qx::cvt::from_json(obj.value("list_join_query_user"), t.m_lstJoinQueryUser, format);
            qx::cvt::from_json(obj.value("list_join_query_resolve"), t.m_lstJoinQueryToResolve, format);

            t.m_pSqlResult.reset();
            if ((lstResultPosByKey.count() > 0) || (lstResultValues.count() > 0))
            {
               t.m_pSqlResult = std::shared_ptr<qx::QxSqlQuery::QxSqlResult>(new qx::QxSqlQuery::QxSqlResult());
               t.m_pSqlResult->positionByKey = lstResultPosByKey;
               t.m_pSqlResult->values = lstResultValues;
            }

            t.m_pSqlElementTemp.reset();
            qx::dao::detail::IxSqlElement::type_class eTypeSqlElement = qx::dao::detail::IxSqlElement::_no_type;
            eTypeSqlElement = static_cast<qx::dao::detail::IxSqlElement::type_class>(qRound(obj.value("sql_element_temp_type").toDouble()));
            if (eTypeSqlElement != qx::dao::detail::IxSqlElement::_no_type)
            {
               t.m_pSqlElementTemp = qx::dao::detail::create_sql_element(eTypeSqlElement);
               qAssert(t.m_pSqlElementTemp);
               if (t.m_pSqlElementTemp)
               {
                  qx::cvt::from_json(obj.value("sql_element_temp"), (*t.m_pSqlElementTemp), format);
               }
            }

            t.m_lstSqlElement.clear();
            QJsonArray arr = obj.value("sql_element_list").toArray();
            for (int i = 0; i < arr.count(); i++)
            {
               QJsonValue val = arr.at(i);
               if (!val.isObject())
               {
                  continue;
               }
               QJsonObject item = val.toObject();
               qx::dao::detail::IxSqlElement_ptr pSqlElement;
               eTypeSqlElement = qx::dao::detail::IxSqlElement::_no_type;
               eTypeSqlElement = static_cast<qx::dao::detail::IxSqlElement::type_class>(qRound(item.value("sql_element_type").toDouble()));
               if (eTypeSqlElement != qx::dao::detail::IxSqlElement::_no_type)
               {
                  pSqlElement = qx::dao::detail::create_sql_element(eTypeSqlElement);
                  qAssert(pSqlElement);
                  if (pSqlElement)
                  {
                     qx::cvt::from_json(item.value("sql_element"), (*pSqlElement), format);
                  }
               }
               t.m_lstSqlElement.append(pSqlElement);
            }

            return qx_bool(true);
         }

      } // namespace detail
   } // namespace cvt
} // namespace qx

#endif // _QX_NO_JSON
