/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.apache.carbondata.spark.testsuite.dataload

import org.apache.spark.sql.Row
import org.apache.spark.sql.test.util.QueryTest
import org.scalatest.{BeforeAndAfterAll, BeforeAndAfterEach}

import org.apache.carbondata.core.constants.CarbonCommonConstants
import org.apache.carbondata.core.util.CarbonProperties

class TestLoadWithSortTempCompressed extends QueryTest
  with BeforeAndAfterEach with BeforeAndAfterAll {
  val originOffHeapStatus: String = CarbonProperties.getInstance()
    .getProperty(CarbonCommonConstants.ENABLE_OFFHEAP_SORT,
      CarbonCommonConstants.ENABLE_OFFHEAP_SORT_DEFAULT)
  val originSortTempCompressor: String = CarbonProperties.getInstance()
    .getProperty(CarbonCommonConstants.CARBON_SORT_TEMP_COMPRESSOR,
      CarbonCommonConstants.CARBON_SORT_TEMP_COMPRESSOR_DEFAULT)
  val simpleTable = "simpleTable"
  val complexCarbonTable = "complexCarbonTable"
  val complexHiveTable = "complexHiveTable"

  override def beforeEach(): Unit = {
    sql(s"drop table if exists $simpleTable")
    sql(s"drop table if exists $complexCarbonTable")
    sql(s"drop table if exists $complexHiveTable")
  }

  override def afterEach(): Unit = {
    sql(s"drop table if exists $simpleTable")
    sql(s"drop table if exists $complexCarbonTable")
    sql(s"drop table if exists $complexHiveTable")
  }


  override protected def beforeAll(): Unit = {
  }

  override def afterAll(): Unit = {
    CarbonProperties.getInstance()
      .addProperty(CarbonCommonConstants.CARBON_SORT_TEMP_COMPRESSOR,
        originSortTempCompressor)
    CarbonProperties.getInstance()
      .addProperty(CarbonCommonConstants.ENABLE_OFFHEAP_SORT, originOffHeapStatus)
  }

  private def testSimpleTable(): Unit = {
    val lineNum: Int = 10002
    val df = {
      import sqlContext.implicits._
      sqlContext.sparkContext.parallelize((1 to lineNum).reverse)
        .map(x => (s"a$x", s"b$x", s"c$x", 12.3 + x, x, System.currentTimeMillis(), s"d$x"))
        .toDF("c1", "c2", "c3", "c4", "c5", "c6", "c7")
    }

    df.write
      .format("carbondata")
      .option("tableName", simpleTable)
      .option("tempCSV", "true")
      .option("DICTIONARY_INCLUDE", "c1,c2")
      .option("SORT_COLUMNS", "c1,c3")
      .save()

    checkAnswer(sql(s"select count(*) from $simpleTable"), Row(lineNum))
    checkAnswer(sql(s"select count(*) from $simpleTable where c5 > 5001"), Row(5001))
  }

  test("test data load for simple table with sort temp compressed with snappy" +
       " and off-heap sort enabled") {
    CarbonProperties.getInstance().addProperty(CarbonCommonConstants.CARBON_SORT_TEMP_COMPRESSOR,
      "SNAPPY")
    CarbonProperties.getInstance().addProperty(CarbonCommonConstants.ENABLE_OFFHEAP_SORT, "true")
    testSimpleTable()
    CarbonProperties.getInstance().addProperty(CarbonCommonConstants.ENABLE_OFFHEAP_SORT,
      originOffHeapStatus)
  }

  test("test data load for simple table with sort temp compressed with snappy" +
       " and off-heap sort disabled") {
    CarbonProperties.getInstance().addProperty(CarbonCommonConstants.CARBON_SORT_TEMP_COMPRESSOR,
      "SNAPPY")
    CarbonProperties.getInstance().addProperty(CarbonCommonConstants.ENABLE_OFFHEAP_SORT, "false")
    testSimpleTable()
    CarbonProperties.getInstance().addProperty(CarbonCommonConstants.ENABLE_OFFHEAP_SORT,
      originOffHeapStatus)
  }

  test("test data load for simple table with sort temp compressed with zstd" +
       " and off-heap sort enabled") {
    CarbonProperties.getInstance().addProperty(CarbonCommonConstants.CARBON_SORT_TEMP_COMPRESSOR,
      "ZSTD")
    CarbonProperties.getInstance().addProperty(CarbonCommonConstants.ENABLE_OFFHEAP_SORT, "true")
    testSimpleTable()
    CarbonProperties.getInstance().addProperty(CarbonCommonConstants.ENABLE_OFFHEAP_SORT,
      originOffHeapStatus)
  }

  test("test data load for simple table with sort temp compressed with zstd" +
       " and off-heap sort disabled") {
    CarbonProperties.getInstance().addProperty(CarbonCommonConstants.CARBON_SORT_TEMP_COMPRESSOR,
      "ZSTD")
    CarbonProperties.getInstance().addProperty(CarbonCommonConstants.ENABLE_OFFHEAP_SORT, "false")
    testSimpleTable()
    CarbonProperties.getInstance().addProperty(CarbonCommonConstants.ENABLE_OFFHEAP_SORT,
      originOffHeapStatus)
  }

  private def testComplexTable(): Unit = {
    // note: following tests are copied from `TestComplexTypeQuery`
    sql(
      s"create table $complexCarbonTable(deviceInformationId int, channelsId string, ROMSize " +
      "string, ROMName String, purchasedate string, mobile struct<imei:string, imsi:string>, MAC " +
      "array<string>, locationinfo array<struct<ActiveAreaId:int, ActiveCountry:string, " +
      "ActiveProvince:string, Activecity:string, ActiveDistrict:string, ActiveStreet:string>>, " +
      "proddate struct<productionDate:string,activeDeactivedate:array<string>>, gamePointId " +
      "double,contractNumber double)  STORED BY 'org.apache.carbondata.format'  TBLPROPERTIES " +
      "('DICTIONARY_INCLUDE'='deviceInformationId', 'DICTIONARY_EXCLUDE'='channelsId'," +
      "'COLUMN_GROUP'='(ROMSize,ROMName)')")
    sql(s"LOAD DATA local inpath '$resourcesPath/complextypesample.csv' INTO table" +
        s" $complexCarbonTable  OPTIONS('DELIMITER'=',', " +
        "'QUOTECHAR'='\"', 'FILEHEADER'='deviceInformationId,channelsId,ROMSize,ROMName," +
        "purchasedate,mobile,MAC,locationinfo,proddate,gamePointId,contractNumber', " +
        "'COMPLEX_DELIMITER_LEVEL_1'='$', 'COMPLEX_DELIMITER_LEVEL_2'=':')")
    sql(
      s"create table $complexHiveTable(deviceInformationId int, channelsId string, ROMSize " +
      "string, ROMName String, purchasedate string,mobile struct<imei:string, imsi:string>,MAC " +
      "array<string>, locationinfo array<struct<ActiveAreaId:int, ActiveCountry:string, " +
      "ActiveProvince:string, Activecity:string, ActiveDistrict:string, ActiveStreet:string>>, " +
      "proddate struct<productionDate:string,activeDeactivedate:array<string>>, gamePointId " +
      "double,contractNumber double)row format delimited fields terminated by ',' collection " +
      "items terminated by '$' map keys terminated by ':'")
    sql(s"LOAD DATA local inpath '$resourcesPath/complextypesample.csv' INTO table" +
        s" $complexHiveTable")

    checkAnswer(sql(s"select * from $complexCarbonTable"), sql(s"select * from $complexHiveTable"))
    checkAnswer(sql(s"select MAC from $complexCarbonTable where MAC[0] = 'MAC1'"),
      sql(s"select MAC from $complexHiveTable where MAC[0] = 'MAC1'"))
    checkAnswer(sql(s"select mobile from $complexCarbonTable where mobile.imei like '1AA%'"),
      sql(s"select mobile from $complexHiveTable where mobile.imei like '1AA%'"))
    checkAnswer(sql(s"select locationinfo from $complexCarbonTable" +
                    " where locationinfo[0].ActiveAreaId > 2 AND locationinfo[0].ActiveAreaId < 7"),
      sql(s"select locationinfo from $complexHiveTable" +
          " where locationinfo[0].ActiveAreaId > 2 AND locationinfo[0].ActiveAreaId < 7"))
  }

  test("test data load for complex table with sort temp compressed with snappy" +
       " and off-heap sort enabled") {
    CarbonProperties.getInstance().addProperty(CarbonCommonConstants.CARBON_SORT_TEMP_COMPRESSOR,
      "SNAPPY")
    CarbonProperties.getInstance().addProperty(CarbonCommonConstants.ENABLE_OFFHEAP_SORT, "true")
    testComplexTable()
    CarbonProperties.getInstance().addProperty(CarbonCommonConstants.ENABLE_OFFHEAP_SORT,
      originOffHeapStatus)
  }

  test("test data load for complex table with sort temp compressed with snappy" +
       " and off-heap sort disabled") {
    CarbonProperties.getInstance().addProperty(CarbonCommonConstants.CARBON_SORT_TEMP_COMPRESSOR,
      "SNAPPY")
    CarbonProperties.getInstance().addProperty(CarbonCommonConstants.ENABLE_OFFHEAP_SORT, "false")
    testComplexTable()
    CarbonProperties.getInstance().addProperty(CarbonCommonConstants.ENABLE_OFFHEAP_SORT,
      originOffHeapStatus)
  }

  test("test data load for complex table with sort temp compressed with zstd" +
       " and off-heap sort enabled") {
    CarbonProperties.getInstance().addProperty(CarbonCommonConstants.CARBON_SORT_TEMP_COMPRESSOR,
      "ZSTD")
    CarbonProperties.getInstance().addProperty(CarbonCommonConstants.ENABLE_OFFHEAP_SORT, "true")
    testComplexTable()
    CarbonProperties.getInstance().addProperty(CarbonCommonConstants.ENABLE_OFFHEAP_SORT,
      originOffHeapStatus)
  }

  test("test data load for complex table with sort temp compressed with zstd" +
       " and off-heap sort disabled") {
    CarbonProperties.getInstance().addProperty(CarbonCommonConstants.CARBON_SORT_TEMP_COMPRESSOR,
      "ZSTD")
    CarbonProperties.getInstance().addProperty(CarbonCommonConstants.ENABLE_OFFHEAP_SORT, "false")
    testComplexTable()
    CarbonProperties.getInstance().addProperty(CarbonCommonConstants.ENABLE_OFFHEAP_SORT,
      originOffHeapStatus)
  }
}
