/*
  * (non-Javadoc)
  *
  * @see org.eclipse.php.debug.core.debugger.parameters.
  * IDebugParametersInitializer
  * #getRequestURL(org.eclipse.debug.core.ILaunch)
  */
 public URL getRequestURL(ILaunch launch) {
   String url = launch.getAttribute(IDebugParametersKeys.ORIGINAL_URL);
   try {
     return new URL(url);
   } catch (MalformedURLException e) {
     Logger.logException("Malformed URL: " + url, e); // $NON-NLS-1$
   }
   return null;
 }
 private static boolean filesAreIdentical(int requestSize, int requestChecksum, byte[] content) {
   int checksum;
   if (requestSize == content.length) {
     checksum = calcCheckSum(content);
     return (requestChecksum == checksum);
   }
   try {
     // checking if the difference is just the line ending - \n instead
     // of \r\n or \n\r
     int numOfNewLine = 0;
     byte slashR = 13;
     byte slashN = 10;
     // counting lineBreaks
     for (byte element : content) {
       if (element == slashN) {
         numOfNewLine++;
       }
     }
     if (requestSize == content.length + numOfNewLine) {
       byte newContent[] = new byte[content.length + numOfNewLine];
       int newContentIndex = 0;
       // changing every \n to \r\n
       for (byte element : content) {
         if (element == slashN) {
           newContent[newContentIndex] = slashR;
           newContentIndex++;
         }
         newContent[newContentIndex] = element;
         newContentIndex++;
       }
       checksum = calcCheckSum(newContent);
       if (requestChecksum == checksum) {
         return true;
       }
       // changing \r\n to \n\r
       for (int index = 0; index < content.length; index++) {
         if (content[index] == slashN) {
           newContent[index] = slashR;
         } else if (content[index] == slashR) {
           newContent[index] = slashN;
         }
       }
       checksum = calcCheckSum(newContent);
       return (requestChecksum == checksum);
     }
   } catch (Exception e) {
     Logger.logException(e);
   }
   return false;
 }
  /**
   * create any environment variables that may be required
   *
   * @param configuration launch configuration
   * @param sessionID the DBGp Session Id
   * @param ideKey the DBGp ide key
   * @return string array containing the environment
   * @throws CoreException rethrown exception
   */
  public String[] createDebugLaunchEnvironment(
      ILaunchConfiguration configuration, String sessionID, String ideKey, IPath phpExe)
      throws CoreException {
    // create XDebug required environment variables, need the
    // session handler to start listening and generate a session id

    String configEnv = "XDEBUG_CONFIG=remote_enable=1 idekey=" + ideKey; // $NON-NLS-1$
    String extraDBGpEnv = "DBGP_IDEKEY=" + ideKey; // $NON-NLS-1$
    String sessEnv = "DBGP_COOKIE=" + sessionID; // $NON-NLS-1$

    Logger.debugMSG("env=" + configEnv + ", Cookie=" + sessEnv); // $NON-NLS-1$ //$NON-NLS-2$

    String[] envVarString =
        PHPLaunchUtilities.getEnvironment(
            configuration, new String[] {configEnv, extraDBGpEnv, sessEnv, getLibraryPath(phpExe)});
    return envVarString;
  }
  public void launch(
      ILaunchConfiguration configuration, String mode, ILaunch launch, IProgressMonitor monitor)
      throws CoreException {

    if (monitor.isCanceled()) {
      DebugPlugin.getDefault().getLaunchManager().removeLaunch(launch);
      return;
    }
    PHPexeItem phpExeItem = PHPLaunchUtilities.getPHPExe(configuration);
    if (phpExeItem == null) {
      Logger.log(Logger.ERROR, "Launch configuration could not find PHP exe item"); // $NON-NLS-1$
      monitor.setCanceled(true);
      monitor.done();
      return;
    }
    // get the launch info: php exe, php ini
    final String phpExeString =
        configuration.getAttribute(IPHPDebugConstants.ATTR_EXECUTABLE_LOCATION, (String) null);
    final String phpIniString =
        configuration.getAttribute(IPHPDebugConstants.ATTR_INI_LOCATION, (String) null);
    final String phpScriptString =
        configuration.getAttribute(IPHPDebugConstants.ATTR_FILE, (String) null);
    if (phpScriptString == null || phpScriptString.trim().length() == 0) {
      DebugPlugin.getDefault().getLaunchManager().removeLaunch(launch);
      displayErrorMessage(PHPDebugCoreMessages.XDebug_ExeLaunchConfigurationDelegate_0);
      return;
    }
    if (monitor.isCanceled()) {
      DebugPlugin.getDefault().getLaunchManager().removeLaunch(launch);
      return;
    }

    // locate the project from the php script
    final IWorkspaceRoot workspaceRoot = ResourcesPlugin.getWorkspace().getRoot();
    final IPath filePath = new Path(phpScriptString);
    final IResource scriptRes = workspaceRoot.findMember(filePath);
    if (scriptRes == null) {
      DebugPlugin.getDefault().getLaunchManager().removeLaunch(launch);
      displayErrorMessage(PHPDebugCoreMessages.XDebug_ExeLaunchConfigurationDelegate_1);
      return;
    }

    // resolve php exe location
    final IPath phpExe = new Path(phpExeString);

    // resolve project directory
    IProject project = scriptRes.getProject();

    // Set Project Name as this is required by the source lookup computer
    // delegate
    final String projectString = project.getFullPath().toString();
    ILaunchConfigurationWorkingCopy wc = null;
    if (configuration.isWorkingCopy()) {
      wc = (ILaunchConfigurationWorkingCopy) configuration;
    } else {
      wc = configuration.getWorkingCopy();
    }
    wc.setAttribute(IPHPDebugConstants.PHP_Project, projectString);
    wc.setAttribute(
        IDebugParametersKeys.TRANSFER_ENCODING, PHPProjectPreferences.getTransferEncoding(project));
    wc.setAttribute(
        IDebugParametersKeys.OUTPUT_ENCODING, PHPProjectPreferences.getOutputEncoding(project));
    wc.doSave();

    if (monitor.isCanceled()) {
      DebugPlugin.getDefault().getLaunchManager().removeLaunch(launch);
      return;
    }

    IPath projectLocation = project.getRawLocation();
    if (projectLocation == null) {
      projectLocation = project.getLocation();
    }

    // resolve the script location, but not relative to anything
    IPath phpFile = scriptRes.getLocation();

    if (monitor.isCanceled()) {
      DebugPlugin.getDefault().getLaunchManager().removeLaunch(launch);
      return;
    }

    // Resolve the PHP ini location
    // Locate the php ini by using the attribute. If the attribute was null,
    // try to locate an ini that exists next to the executable.
    File phpIni =
        (phpIniString != null && new File(phpIniString).exists())
            ? new File(phpIniString)
            : PHPINIUtil.findPHPIni(phpExeString);
    File tempIni = PHPINIUtil.prepareBeforeLaunch(phpIni, phpExeString, project);
    launch.setAttribute(IDebugParametersKeys.PHP_INI_LOCATION, tempIni.getAbsolutePath());

    // add process type to process attributes, basically the name of the exe
    // that was launched
    final Map<String, String> processAttributes = new HashMap<String, String>();
    String programName = phpExe.lastSegment();
    final String extension = phpExe.getFileExtension();
    if (extension != null) {
      programName = programName.substring(0, programName.length() - (extension.length() + 1));
    }
    programName = programName.toLowerCase();

    // used by the console colorer extension to determine what class to use
    // should allow the console color providers and line trackers to work
    // process.setAttribute(IProcess.ATTR_PROCESS_TYPE,
    // IPHPConstants.PHPProcessType);

    processAttributes.put(IProcess.ATTR_PROCESS_TYPE, programName);
    // used by the Console to give that console a name
    processAttributes.put(IProcess.ATTR_CMDLINE, phpScriptString);

    if (monitor.isCanceled()) {
      DebugPlugin.getDefault().getLaunchManager().removeLaunch(launch);
      return;
    }

    // determine the environment variables
    String[] envVarString = null;
    DBGpTarget target = null;
    if (mode.equals(ILaunchManager.DEBUG_MODE)) {
      // check the launch for stop at first line, if not there go to
      // project specifics
      boolean stopAtFirstLine = PHPProjectPreferences.getStopAtFirstLine(project);
      stopAtFirstLine =
          configuration.getAttribute(IDebugParametersKeys.FIRST_LINE_BREAKPOINT, stopAtFirstLine);
      String sessionID = DBGpSessionHandler.getInstance().generateSessionId();
      String ideKey = null;
      if (phpExeItem != null) {
        DBGpProxyHandler proxyHandler =
            DBGpProxyHandlersManager.INSTANCE.getHandler(phpExeItem.getUniqueId());
        if (proxyHandler != null && proxyHandler.useProxy()) {
          ideKey = proxyHandler.getCurrentIdeKey();
          if (proxyHandler.registerWithProxy() == false) {
            displayErrorMessage(
                PHPDebugCoreMessages.XDebug_ExeLaunchConfigurationDelegate_2
                    + proxyHandler.getErrorMsg());
            DebugPlugin.getDefault().getLaunchManager().removeLaunch(launch);
            return;
          }
        } else {
          ideKey = DBGpSessionHandler.getInstance().getIDEKey();
        }
      }
      target = new DBGpTarget(launch, phpFile.lastSegment(), ideKey, sessionID, stopAtFirstLine);
      target.setPathMapper(PathMapperRegistry.getByLaunchConfiguration(configuration));
      DBGpSessionHandler.getInstance().addSessionListener(target);
      envVarString = createDebugLaunchEnvironment(configuration, sessionID, ideKey, phpExe);

      int requestPort = getDebugPort(phpExeItem);
      // Check that the debug daemon is functional
      // DEBUGGER - Make sure that the active debugger id is indeed Zend's
      // debugger
      if (!PHPLaunchUtilities.isDebugDaemonActive(
          requestPort, XDebugCommunicationDaemon.XDEBUG_DEBUGGER_ID)) {
        PHPLaunchUtilities.showLaunchErrorMessage(
            NLS.bind(
                PHPDebugCoreMessages.ExeLaunchConfigurationDelegate_PortInUse,
                requestPort,
                phpExeItem.getName()));
        monitor.setCanceled(true);
        monitor.done();
        return;
      }

    } else {
      envVarString =
          PHPLaunchUtilities.getEnvironment(configuration, new String[] {getLibraryPath(phpExe)});
    }

    IProgressMonitor subMonitor = new SubProgressMonitor(monitor, 30);
    subMonitor.beginTask(PHPDebugCoreMessages.XDebug_ExeLaunchConfigurationDelegate_3, 10);

    // determine the working directory. default is the location of the
    // script
    IPath workingPath = phpFile.removeLastSegments(1);
    File workingDir = workingPath.makeAbsolute().toFile();

    boolean found = false;
    for (int i = 0; i < envVarString.length && !found; i++) {
      String envEntity = envVarString[i];
      String[] elements = envEntity.split("="); // $NON-NLS-1$
      if (elements.length > 0 && elements[0].equals("XDEBUG_WORKING_DIR")) { // $NON-NLS-1$
        found = true;
        workingPath = new Path(elements[1]);
        File temp = workingPath.makeAbsolute().toFile();
        if (temp.exists()) {
          workingDir = temp;
        }
      }
    }

    // Detect PHP SAPI type and thus where we need arguments
    File phpExeFile = new File(phpExeString);
    String sapiType = null;
    String phpV = null;
    PHPexeItem[] items = PHPexes.getInstance().getAllItems();
    for (PHPexeItem item : items) {
      if (item.getExecutable().equals(phpExeFile)) {
        sapiType = item.getSapiType();
        phpV = item.getVersion();
        break;
      }
    }
    String[] args = null;
    if (PHPexeItem.SAPI_CLI.equals(sapiType)) {
      args = PHPLaunchUtilities.getProgramArguments(launch.getLaunchConfiguration());
    }

    // define the command line for launching
    String[] cmdLine = null;
    cmdLine =
        PHPLaunchUtilities.getCommandLine(
            configuration,
            phpExe.toOSString(),
            tempIni.toString(),
            phpFile.toOSString(),
            args,
            phpV);

    // Launch the process
    final Process phpExeProcess = DebugPlugin.exec(cmdLine, workingDir, envVarString);
    // Attach a crash detector
    new Thread(new ProcessCrashDetector(launch, phpExeProcess)).start();

    IProcess eclipseProcessWrapper = null;
    if (phpExeProcess != null) {
      subMonitor.worked(10);
      eclipseProcessWrapper =
          DebugPlugin.newProcess(launch, phpExeProcess, phpExe.toOSString(), processAttributes);
      if (eclipseProcessWrapper == null) {

        // another error so we stop everything somehow
        phpExeProcess.destroy();
        subMonitor.done();
        DebugPlugin.getDefault().getLaunchManager().removeLaunch(launch);
        throw new CoreException(new Status(IStatus.ERROR, PHPDebugPlugin.ID, 0, null, null));
      }

      // if launching in debug mode, create the debug infrastructure and
      // link it with the launched process
      if (mode.equals(ILaunchManager.DEBUG_MODE) && target != null) {
        target.setProcess(eclipseProcessWrapper);
        launch.addDebugTarget(target);
        subMonitor.subTask(PHPDebugCoreMessages.XDebug_ExeLaunchConfigurationDelegate_4);
        target.waitForInitialSession(
            (DBGpBreakpointFacade) IDELayerFactory.getIDELayer(),
            XDebugPreferenceMgr.createSessionPreferences(),
            monitor);
      }

    } else {
      // we did not launch
      if (mode.equals(ILaunchManager.DEBUG_MODE)) {
        DBGpSessionHandler.getInstance().removeSessionListener(target);
      }
      DebugPlugin.getDefault().getLaunchManager().removeLaunch(launch);
    }
    subMonitor.done();
  }
  /*
   * (non-Javadoc)
   *
   * @seeorg.eclipse.php.internal.debug.core.debugger.parameters.
   * IDebugParametersInitializer
   * #generateQueryParameters(org.eclipse.debug.core.ILaunch)
   */
  public Hashtable<String, String> getDebugParameters(ILaunch launch) {
    Hashtable<String, String> parameters = new Hashtable<String, String>();
    ILaunchConfiguration launchConfiguration = launch.getLaunchConfiguration();
    parameters.put(START_DEBUG, "1"); // $NON-NLS-1$

    String port = launch.getAttribute(IDebugParametersKeys.PORT);
    if (port != null) {
      parameters.put(DEBUG_PORT, port);
    } else {
      PHPDebugPlugin.logErrorMessage(
          "A port was not defined for the DefaultDebugParametersInitializer."); //$NON-NLS-1$
    }

    if (getBooleanValue(launch.getAttribute(IDebugParametersKeys.PASSIVE_DEBUG))) {
      parameters.put(DEBUG_PASSIVE, "1"); // $NON-NLS-1$
    }

    parameters.put(SEND_SESS_END, "1"); // $NON-NLS-1$

    if (getBooleanValue(launch.getAttribute(IDebugParametersKeys.WEB_SERVER_DEBUGGER))) {
      String debugHosts = PHPDebugPlugin.getDebugHosts();
      // Set up custom server debug hosts if any
      if (launchConfiguration != null) {
        try {
          Server server =
              ServersManager.getServer(
                  launchConfiguration.getAttribute(Server.NAME, "")); // $NON-NLS-1$
          String customHosts = ZendDebuggerSettingsUtil.getDebugHosts(server.getUniqueId());
          if (!customHosts.isEmpty()) debugHosts = customHosts;
        } catch (CoreException ce) {
          Logger.logException(ce);
        }
      }
      parameters.put(DEBUG_HOST, debugHosts);

      parameters.put(DEBUG_NO_CACHE, Long.toString(System.currentTimeMillis()));
    }

    if (ILaunchManager.DEBUG_MODE.equals(launch.getLaunchMode())
        && getBooleanValue(launch.getAttribute(IDebugParametersKeys.FIRST_LINE_BREAKPOINT))) {
      parameters.put(DEBUG_STOP, "1"); // $NON-NLS-1$
    }
    String url = launch.getAttribute(IDebugParametersKeys.ORIGINAL_URL);
    if (url != null) {
      parameters.put(ORIGINAL_URL, url);
    }
    if (launchConfiguration != null) {
      try {
        String sessionSetting =
            launchConfiguration.getAttribute(
                IPHPDebugConstants.DEBUGGING_PAGES, IPHPDebugConstants.DEBUGGING_ALL_PAGES);
        if (IPHPDebugConstants.DEBUGGING_ALL_PAGES.equals(sessionSetting)) {
          parameters.put(DEBUG_ALL_PAGES, "1"); // $NON-NLS-1$
        } else if (IPHPDebugConstants.DEBUGGING_FIRST_PAGE.equals(sessionSetting)) {
          parameters.put(DEBUG_FIRST_PAGE, "1"); // $NON-NLS-1$
        } else if (IPHPDebugConstants.DEBUGGING_START_FROM.equals(sessionSetting)) {
          parameters.put(
              DEBUG_START_URL,
              launchConfiguration.getAttribute(
                  IPHPDebugConstants.DEBUGGING_START_FROM_URL, "")); // $NON-NLS-1$
          if (launchConfiguration.getAttribute(
              IPHPDebugConstants.DEBUGGING_SHOULD_CONTINUE, false)) {
            parameters.put(DEBUG_CONTINUE, "1"); // $NON-NLS-1$
          }
        }
      } catch (CoreException ce) {
        Logger.logException(ce);
      }
    }
    String sessID = launch.getAttribute(IDebugParametersKeys.SESSION_ID);
    if (sessID != null) {
      parameters.put(DEBUG_SESSION_ID, sessID);
    }

    return parameters;
  }