package net.northking.cctp.commands.win;

import net.northking.cctp.commands.OSCommand;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;

public class TaskList implements OSCommand
{
  private static final Logger logger = LoggerFactory.getLogger(TaskList.class);
  /**
   * 命令名称
   */
  private static final String COMMAND_NAME = "TASKLIST";

  private String computer;
  private String username;
  private String password;
  private String module;
  private boolean details = false;
  private Format format;
  private List<String> filters = new ArrayList<>();

  /**
   * /S <computer>　指定连接到的计算机或IP地址，默认本机。
   *
   * @param computer 计算机或IP地址
   */
  public void computer(String computer)
  {
    this.computer = computer;
  }

  /**
   * /u [<Domain>\]<UserName>　指定使用哪个用户执行这个命令。
   *
   * @param username 用户
   */
  public void username(String username)
  {
    this.username = username;
  }

  /**
   * /P 为指定的用户指定密码。
   *
   * @param password 密码
   */
  public void password(String password)
  {
    this.password = password;
  }

  /**
   * 列出调用指定的DLL模块的所有进程。如果没有指定模块名，显示每个进程加载的所有模块。
   *
   * @param module 模块
   */
  public void module(String module)
  {
    this.module = module;
  }

  /**
   * 显示详细信息。
   */
  public void details(boolean details)
  {
    this.details = details;
  }

  public void format(Format format)
  {
    this.format = format;
  }

  /**
   * 显示一系列符合筛选器指定的进程。
   *
   * @param filter 筛选器
   */
  public void filter(String filter)
  {
    this.filters.add(filter);
  }

  private String build()
  {
    StringBuilder command = new StringBuilder(COMMAND_NAME);

    if (computer != null && computer.trim().length() > 0)
    {
      command.append(" /S ").append(computer);
    }
    if (username != null && username.trim().length() > 0)
    {
      command.append(" /u ").append(username);
    }
    if (password != null && password.trim().length() > 0)
    {
      command.append(" /P ").append(password);
    }
    if (module != null && module.trim().length() > 0)
    {
      command.append(" /M ").append(module);
    }
    if (details)
    {
      command.append(" /V");
    }
    if (format != null)
    {
      command.append(" /FO ").append(format.name());
    }
    for (String filter : filters)
    {
      command.append(" /FI ").append("\"").append(filter).append("\"");
    }
    return command.toString();
  }

  public List<Result> execute()
  {
    List<Result> resultList = new ArrayList<>();
    String commandStr = build();
    String line;
    Process process;
    int lineNo = 1;
    try
    {
      logger.debug("执行命令：{}", commandStr);
      process = Runtime.getRuntime().exec("cmd /c " + commandStr);
      BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(process.getInputStream(), "GBK"));
      while ((line = bufferedReader.readLine()) != null)
      {
        logger.debug("行-{}： {}", lineNo, line);
        if (lineNo > 1)
        {
          resultList.add(new Result(line));
        }
        lineNo++;
      }
      process.waitFor();
    } catch (IOException | InterruptedException e)
    {
      logger.error("使用 TASKLIST 命令获取进程PID时发生异常。", e);
    }

    return resultList;
  }

  public enum Format
  {
    table,
    list,
    csv
  }


  public class Result
  {
    public static final String IMAGENAME = "IMAGENAME";
    public static final String PID = "PID";

    private final String imageName;
    private final String pid;
    private final String sessionName;
    private final String sessionCount;
    private final String memory;

    public Result(String line)
    {
      String[] args = line.split("\",\"");
      imageName = args[0].substring(1);
      pid = args[1];
      sessionName = args[2];
      sessionCount = args[3];
      memory = args[4].replace("\"", "");
    }

    public Result(String imageName, String pid, String sessionName, String sessionCount, String memory)
    {
      this.imageName = imageName;
      this.pid = pid;
      this.sessionName = sessionName;
      this.sessionCount = sessionCount;
      this.memory = memory;
    }

    public String getImageName()
    {
      return imageName;
    }

    public String getPid()
    {
      return pid;
    }

    public String getSessionName()
    {
      return sessionName;
    }

    public String getSessionCount()
    {
      return sessionCount;
    }

    public String getMemory()
    {
      return memory;
    }

    @Override
    public String toString()
    {
      return "imageName=" + imageName + ", pid=" + pid + ", sessionName=" + sessionName + ", sessionCount=" + sessionCount + ", memory=" + memory;
    }
  }
}
