package mobvista.dmp.common

import org.apache.commons.cli.{BasicParser, CommandLine, HelpFormatter, Option, Options}
import org.apache.commons.lang.StringUtils

import java.util.regex.Pattern
import scala.collection.JavaConversions._

/**
  * spark应用程序模板类
  */
abstract class CommonSparkJob {
         // oaid的正则有以下两种形式didPtn和oaidAnotherPtn，参考 https://www.h5w3.com/33786.html
  val QUERY = "QUERY"
  val ENCODING = "UTF-8"
  val HTTPPREFIX = "http://test.com"
  val DATA_SPLIT = "\t"
  val imeiMd5Ptn = "^([a-fA-F0-9]{32})$"
  val oaidAnotherPtn = "^([a-fA-F0-9]{1,64})$"

  //  IDFA/GAID
  val didPtn = "^[0-9a-fA-F]{8}(-[0-9a-fA-F]{4}){3}-[0-9a-fA-F]{12}$"
  //  全0
  val allZero = "00000000-0000-0000-0000-000000000000"
  //  IMEI
  val imeiPtn = "^([0-9]{14,17})$"
  //  14~16位连续多位相同字符，非法IMEI过滤
  val imeiPtnAll = """^([0-9])\1{14,16}"""
  //  androidId
  val andriodIdPtn = "^[a-zA-Z0-9]{15,17}$"
  //  连续多位相同字符，非法 androidId 过滤
  val andriodIdAll = "^[a-zA-Z0-9]\1{15}$"
  //  MD5
  val md5Ptn = "^([a-fA-F0-9]{32})$"
  //  连续多位相同字符，非法 IMEI MD5 过滤
  val umd5Ptn = """^([0-9A-Za-z])\1{29,31}"""
  //  OAID
  val oaidPtb = """^[0-9A-Za-z-]{16,64}$"""
  //  IP
  val ipPtn = """^(25[0-5]|2[0-4][0-9]|[0-1]?[0-9]?[0-9])(\.(25[0-5]|2[0-4][0-9]|[0-1]?[0-9]?[0-9])){3}$"""
  //  Date
  val datePtn = """^\d{4}-\d{2}-\d{2}"""

  val iOSPkgPtn = Pattern.compile("^\\d+$")
  val iOSIDPkgPtn = Pattern.compile("^id\\d+$")
  val androidPkgPtn = Pattern.compile("^(?=^.{3,255}$)[a-zA-Z0-9_][-a-zA-Z0-9_]{0,62}(\\.[a-zA-Z0-9_][-a-zA-Z0-9_]{0,62})+$")


  val options = buildOptions()
  val commParser = new BasicParser

  protected def run(args: Array[String]): Int

  protected def checkMustOption(commands: CommandLine): Boolean = {
    val collect = options.getOptions
    collect.foreach(opt => {
      val option = opt.asInstanceOf[Option]
      val desc = option.getDescription
      if (desc.contains("[must]")) {
        val value = commands.getOptionValue(option.getOpt)
        if (StringUtils.isEmpty(value)) {
          println("Please set paramter " + option.getArgName)
          return false
        }
      }
    })
    true
  }

  protected def buildOptions(): Options = {
    val options = new Options
    options.addOption("input", true, "[must] input path")
    options.addOption("output", true, "[must] output path")
    options.addOption("parallelism", true, "parallelism of shuffle operation")
    options.addOption("coalesce", true, "number of output files")
    options
  }

  protected def printOptions (commandLine: CommandLine): Unit = {
    val collect = options.getOptions
    println("****************************************")
    collect.foreach(option => {
      val opt = option.asInstanceOf[Option].getOpt
      val value = commandLine.getOptionValue(opt)
      println(s"* $opt = $value")
    })
    println("****************************************")
  }

  protected def printUsage(options: Options): Unit = {
    val help = new HelpFormatter
    help.printHelp(this.getClass.getSimpleName, options)
  }

  def splitFun(line : String, split : String) : Array[String] = {
    if (split == null) {
      StringUtils.splitPreserveAllTokens(line, DATA_SPLIT, -1)
    } else {
      StringUtils.splitPreserveAllTokens(line, split, -1)
    }
  }

  def splitFun(line : String) : Array[String] = {
    splitFun(line, null)
  }
}
