# Author: srazbash
###############################################################################

unParameteriseTBATS <- function(param.vector, control) {
  # print(control)
  if (control$use.box.cox) {
    lambda <- param.vector[1]
    alpha <- param.vector[2]
    if (control$use.beta) {
      if (control$use.damping) {
        small.phi <- param.vector[3]
        beta <- param.vector[4]
        gamma.start <- 5
      } else {
        small.phi <- 1
        beta <- param.vector[3]
        gamma.start <- 4
      }
    } else {
      small.phi <- NULL
      beta <- NULL
      gamma.start <- 3
    }
    if (control$length.gamma > 0) {
      gamma.one.vector <- param.vector[
        gamma.start:(gamma.start + (control$length.gamma / 2) - 1)
      ]
      gamma.two.vector <- param.vector[
        (gamma.start + (control$length.gamma / 2)):(gamma.start +
          (control$length.gamma) -
          1)
      ]
      final.gamma.pos <- gamma.start + control$length.gamma - 1
    } else {
      gamma.one.vector <- NULL
      gamma.two.vector <- NULL
      final.gamma.pos <- gamma.start - 1
    }
    if (control$p != 0) {
      ar.coefs <- param.vector[
        (final.gamma.pos + 1):(final.gamma.pos + control$p)
      ]
    } else {
      ar.coefs <- NULL
    }
    if (control$q != 0) {
      ma.coefs <- param.vector[
        (final.gamma.pos + control$p + 1):length(param.vector)
      ]
    } else {
      ma.coefs <- NULL
    }
  } else {
    lambda <- NULL
    alpha <- param.vector[1]
    if (control$use.beta) {
      if (control$use.damping) {
        small.phi <- param.vector[2]
        beta <- param.vector[3]
        gamma.start <- 4
      } else {
        small.phi <- 1
        beta <- param.vector[2]
        gamma.start <- 3
      }
    } else {
      small.phi <- NULL
      beta <- NULL
      gamma.start <- 2
    }
    if (control$length.gamma > 0) {
      gamma.one.vector <- param.vector[
        gamma.start:(gamma.start + (control$length.gamma / 2) - 1)
      ]
      gamma.two.vector <- param.vector[
        (gamma.start + (control$length.gamma / 2)):(gamma.start +
          (control$length.gamma) -
          1)
      ]
      final.gamma.pos <- gamma.start + control$length.gamma - 1
    } else {
      gamma.one.vector <- NULL
      gamma.two.vector <- NULL
      final.gamma.pos <- gamma.start - 1
    }
    if (control$p != 0) {
      ar.coefs <- param.vector[
        (final.gamma.pos + 1):(final.gamma.pos + control$p)
      ]
    } else {
      ar.coefs <- NULL
    }
    if (control$q != 0) {
      ma.coefs <- param.vector[
        (final.gamma.pos + control$p + 1):length(param.vector)
      ]
    } else {
      ma.coefs <- NULL
    }
  }
  list(
    lambda = lambda,
    alpha = alpha,
    beta = beta,
    small.phi = small.phi,
    gamma.one.v = gamma.one.vector,
    gamma.two.v = gamma.two.vector,
    ar.coefs = ar.coefs,
    ma.coefs = ma.coefs
  )
}

makeParscale <- function(control) {
  if (control$use.box.cox) {
    parscale <- c(.001, .01)
  } else {
    parscale <- .01
  }
  if (control$use.beta) {
    if (control$use.damping) {
      parscale <- c(parscale, 1e-2, 1e-2)
    } else {
      parscale <- c(parscale, 1e-2)
    }
  }
  if (control$length.gamma > 0) {
    parscale <- c(parscale, rep(1e-5, control$length.gamma))
  }

  if ((control$p != 0) || (control$q != 0)) {
    parscale <- c(parscale, rep(1e-1, (control$p + control$q)))
  }
  parscale
}
##############################################################################################################################################################################################
## BATS related stuff below
########################################
makeParscaleBATS <- function(control) {
  if (control$use.box.cox) {
    parscale <- c(.001, .1)
  } else {
    parscale <- .1
  }
  if (control$use.beta) {
    if (control$use.damping) {
      parscale <- c(parscale, 1e-2, 1e-2)
    } else {
      parscale <- c(parscale, 1e-2)
    }
  }
  if (control$length.gamma > 0) {
    parscale <- c(parscale, rep(1e-2, control$length.gamma))
  }

  if ((control$p != 0) || (control$q != 0)) {
    parscale <- c(parscale, rep(1e-1, (control$p + control$q)))
  }
  parscale
}

parameterise <- function(
  alpha,
  beta.v = NULL,
  small.phi = 1,
  gamma.v = NULL,
  lambda = NULL,
  ar.coefs = NULL,
  ma.coefs = NULL
) {
  # print("urg")
  # print(lambda)
  if (!is.null(lambda)) {
    param.vector <- cbind(lambda, alpha)
    use.box.cox <- TRUE
  } else {
    # print("hello")
    param.vector <- alpha
    use.box.cox <- FALSE
    # print(use.box.cox)
  }
  if (!is.null(beta.v)) {
    use.beta <- TRUE
    if (is.null(small.phi)) {
      use.damping <- FALSE
    } else if (small.phi != 1) {
      param.vector <- cbind(param.vector, small.phi)
      use.damping <- TRUE
    } else {
      use.damping <- FALSE
    }
    param.vector <- cbind(param.vector, beta.v)
  } else {
    use.beta <- FALSE
    use.damping <- FALSE
  }
  if (!is.null(gamma.v)) {
    gamma.v <- matrix(gamma.v, nrow = 1, ncol = length(gamma.v))
    param.vector <- cbind(param.vector, gamma.v)
    length.gamma <- length(gamma.v)
  } else {
    length.gamma <- 0
  }
  if (!is.null(ar.coefs)) {
    ar.coefs <- matrix(ar.coefs, nrow = 1, ncol = length(ar.coefs))
    param.vector <- cbind(param.vector, ar.coefs)
    p <- length(ar.coefs)
  } else {
    p <- 0
  }
  if (!is.null(ma.coefs)) {
    ma.coefs <- matrix(ma.coefs, nrow = 1, ncol = length(ma.coefs))
    param.vector <- cbind(param.vector, ma.coefs)
    q <- length(ma.coefs)
  } else {
    q <- 0
  }
  # print(use.box.cox)
  control <- list(
    use.beta = use.beta,
    use.box.cox = use.box.cox,
    use.damping = use.damping,
    length.gamma = length.gamma,
    p = p,
    q = q
  )
  list(vect = as.numeric(param.vector), control = control)
}

unParameterise <- function(param.vector, control) {
  # print(control)
  if (control$use.box.cox) {
    lambda <- param.vector[1]
    alpha <- param.vector[2]
    if (control$use.beta) {
      if (control$use.damping) {
        small.phi <- param.vector[3]
        beta <- param.vector[4]
        gamma.start <- 5
      } else {
        small.phi <- 1
        beta <- param.vector[3]
        gamma.start <- 4
      }
    } else {
      small.phi <- NULL
      beta <- NULL
      gamma.start <- 3
    }
    if (control$length.gamma > 0) {
      gamma.vector <- param.vector[
        gamma.start:(gamma.start + control$length.gamma - 1)
      ]
      final.gamma.pos <- gamma.start + control$length.gamma - 1
    } else {
      gamma.vector <- NULL
      final.gamma.pos <- gamma.start - 1
    }
    if (control$p != 0) {
      ar.coefs <- param.vector[
        (final.gamma.pos + 1):(final.gamma.pos + control$p)
      ]
    } else {
      ar.coefs <- NULL
    }
    if (control$q != 0) {
      ma.coefs <- param.vector[
        (final.gamma.pos + control$p + 1):length(param.vector)
      ]
    } else {
      ma.coefs <- NULL
    }
  } else {
    lambda <- NULL
    alpha <- param.vector[1]
    if (control$use.beta) {
      if (control$use.damping) {
        small.phi <- param.vector[2]
        beta <- param.vector[3]
        gamma.start <- 4
      } else {
        small.phi <- 1
        beta <- param.vector[2]
        gamma.start <- 3
      }
    } else {
      small.phi <- NULL
      beta <- NULL
      gamma.start <- 2
    }
    if (control$length.gamma > 0) {
      gamma.vector <- param.vector[
        gamma.start:(gamma.start + control$length.gamma - 1)
      ]
      final.gamma.pos <- gamma.start + control$length.gamma - 1
    } else {
      gamma.vector <- NULL
      final.gamma.pos <- gamma.start - 1
    }
    if (control$p != 0) {
      ar.coefs <- param.vector[
        (final.gamma.pos + 1):(final.gamma.pos + control$p)
      ]
    } else {
      ar.coefs <- NULL
    }
    if (control$q != 0) {
      ma.coefs <- param.vector[
        (final.gamma.pos + control$p + 1):length(param.vector)
      ]
    } else {
      ma.coefs <- NULL
    }
  }
  list(
    lambda = lambda,
    alpha = alpha,
    beta = beta,
    small.phi = small.phi,
    gamma.v = gamma.vector,
    ar.coefs = ar.coefs,
    ma.coefs = ma.coefs
  )
}
