/**
 * Copyright (c) 2013, Groupon, Inc.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * Redistributions of source code must retain the above copyright notice,
 * this list of conditions and the following disclaimer.
 *
 * Redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution.
 *
 * Neither the name of GROUPON nor the names of its contributors may be
 * used to endorse or promote products derived from this software without
 * specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
 * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

 * Created with IntelliJ IDEA.
 * User: Dima Kovalenko (@dimacus) && Darko Marinov
 * Date: 5/10/13
 * Time: 4:06 PM
 */

package com.groupon.seleniumgridextras;

import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;

import com.groupon.seleniumgridextras.config.RuntimeConfig;

import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class PortChecker {

  public static JsonObject getParsedPortInfo(String port) {

    JsonObject status = getPortInfo(port);
    JsonArray standardOut = (JsonArray) status.get("out");

    if(RuntimeConfig.getOS().isWindows())
        return parseWindowsInfo(standardOut);
    return parseLinuxInfo(standardOut);

  }

  public static JsonObject getParsedPortInfo(int port){
    return getParsedPortInfo(String.valueOf(port));
  }

  public static JsonObject getPortInfo(String port) {
    StringBuilder command = new StringBuilder();

    command.append(getCommand());

    if (!port.equals("")) {
      command.append(getParameters());
      command.append(port);
    }

    return ExecuteCommand.execRuntime(command.toString());
  }

  private static JsonObject parseLinuxInfo(JsonArray status) {
    JsonObject info = new JsonObject();
    info.addProperty("out", status.toString());

    for (JsonElement line : status) {
      Matcher m = Pattern.compile("(\\w*)\\s*(\\d*)\\s*(\\w*)\\s*.*(\\(LISTEN\\))").matcher(
          line.getAsString());
      if (m.find()) {
        info.addProperty("process", m.group(1));
        info.addProperty("pid", m.group(2));
        info.addProperty("user", m.group(3));
        break;
      }
    }
    return info;
  }
  
    private static JsonObject parseWindowsInfo(JsonArray status) {

        JsonObject info = new JsonObject();

        for (JsonElement line : status) {
            Matcher m = Pattern.compile("\\s*(TCP)\\s*([0-9.:]*)\\s*([0-9.:]*)\\s*(LISTENING)\\s*(\\d*)").matcher(line.getAsString());
            if (m.find()) {
                info.addProperty("pid", m.group(5));
                break;
            }
        }

        return info;
    }


  private static String getCommand() {
    if (RuntimeConfig.getOS().isWindows()) {
      return "netstat -aon ";
    } else {
      return "lsof -i TCP";
    }
  }

  private static String getParameters() {
    if (RuntimeConfig.getOS().isWindows()) {
      return " | findstr :";
    } else {
      return ":";
    }
  }

}

@@ -2135,16 +2135,17 @@
 %0A%0A    if
+ 
 (Runtime
@@ -2171,19 +2171,19 @@
 ndows())
-%0A  
+ %7B%0A
       re
@@ -2214,24 +2214,31 @@
 andardOut);%0A
+    %7D%0A%0A
     return p
@@ -2325,16 +2325,17 @@
 nt port)
+ 
 %7B%0A    re
@@ -3220,13 +3220,9 @@
   %7D%0A
-  %0A  
+%0A
   pr
@@ -3283,20 +3283,16 @@
 tus) %7B%0A%0A
-    
     Json
@@ -3324,20 +3324,16 @@
 ect();%0A%0A
-    
     for 
@@ -3358,30 +3358,24 @@
 : status) %7B%0A
-      
       Matche
@@ -3367,36 +3367,56 @@
  %7B%0A      Matcher
- m =
+%0A          m =%0A         
  Pattern.compile
@@ -3481,16 +3481,31 @@
 (%5C%5Cd*)%22)
+%0A              
 .matcher
@@ -3532,22 +3532,16 @@
 ;%0A      
-     
- 
 if (m.fi
@@ -3548,24 +3548,16 @@
 nd()) %7B%0A
-        
         
@@ -3601,24 +3601,16 @@
         
-  
-      
 break;%0A 
@@ -3618,35 +3618,21 @@
     
-     
- 
 %7D%0A    
-  
-  
 %7D%0A%0A    
- 
-   
 retu
@@ -3640,18 +3640,16 @@
 n info;%0A
-  
   %7D%0A%0A%0A  
@@ -3792,16 +3792,29 @@
 n %22lsof 
+-sTCP:LISTEN 
 -i TCP%22;

Tweak the lsof command to only return the PIDs of listening ports not connected ones