package net.sourceforge.phpeclipse.phpeditor;

import java.io.IOException;
import java.io.InputStream;

import net.sourceforge.phpeclipse.PHPeclipsePlugin;

import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IMarker;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.jface.preference.IPreferenceStore;
import org.eclipse.jface.text.source.ISourceViewer;
import org.eclipse.ui.IEditorInput;
import org.eclipse.ui.IFileEditorInput;
import org.eclipse.ui.editors.text.TextEditor;

import test.PHPParserManager;
import test.PHPParserSuperclass;


public class PHPSyntaxParserThread extends Thread {
  private static String[] EXTENSIONS = { ".php", ".php3", ".php4", ".inc", ".phtml" };

	private String text = "";
	private String previousText = "";

	private boolean stopValidation = false;
	private boolean validationTerminated = false;
	private boolean isActive = false;

	private TextEditor fTextEditor;
	private ISourceViewer fSourceViewer;

	private int previousHashCode = 0;
	// Defaults
	private int validationInterval = 2000; //millis
	private int waitForTermination = 400; // millis
	private int maxErrorsShown = 10;

	public PHPSyntaxParserThread(
		TextEditor textEditor,
		ISourceViewer viewer) {
		super();
		fTextEditor = textEditor;
		fSourceViewer = viewer;
	}

	public void setText(String text) {
		if (!isActive)
			this.text = text;
	}

	public void setText(String text, boolean forceUpdate) {
		if (!isActive) {
			this.text = text;
		}

		if (forceUpdate) {
			this.previousText = "";
			this.previousHashCode = 0;
		}
	}

	public String getText() {
		return text;
	}

	public void setInterval(int millis) {
		this.validationInterval = millis;
	}

	public int getInterval() {
		return validationInterval;
	}

	public void setErrorsShown(int number) {
		this.maxErrorsShown = number;
	}

	public int getErrorsShown() {
		return maxErrorsShown;
	}

	public void dispose() {
		this.stopValidation = true;

		if (validationTerminated == false) {

			try {
				Thread.sleep(waitForTermination);
			} catch (Exception e) {
			}
		}
	}

	public void run() {
		while (stopValidation == false) {
			try {

				this.isActive = true;
				boolean ret = this.validateSyntax();

				this.previousText = this.text;
				this.isActive = false;

				Thread.sleep(validationInterval);

			} catch (Exception e) {
				e.printStackTrace();
			}
		}

		this.validationTerminated = true;
	}

	public boolean validateSyntax() {

    boolean phpFlag = false;
    try {
      IFile fileToParse = getPHPFile(fTextEditor.getEditorInput());
      if (fileToParse == null) {
        // should never happen
        System.err.println("Error : no file in the editor");
        // should throw an exception
        return false;
      }
      String name = fileToParse.getName();
      for (int i = 0; i<EXTENSIONS.length; i++) {
        if (name.endsWith(EXTENSIONS[i])) {
          phpFlag = true;  // php file extension
          break;
        }
      }
      if (phpFlag) {
        IPreferenceStore store = PHPeclipsePlugin.getDefault().getPreferenceStore();
        if (store.getString(PHPeclipsePlugin.PHP_PARSER_DEFAULT).equals(PHPeclipsePlugin.PHP_INTERNAL_PARSER)) {
          // first delete all the previous markers
          fileToParse.deleteMarkers(IMarker.PROBLEM, false, 0);

          try {
            InputStream iStream = fileToParse.getContents();
            //        int c = iStream.read();
            parse(fileToParse, iStream);
            iStream.close();
          } catch (IOException e) {
          }
        } else {
          PHPParserSuperclass.phpExternalParse(fileToParse);
        }
      }
    } catch (CoreException e) {
    }

 
//
//		Process proc = null;
//
//		if (this.previousText.equals(this.text)) {
//			return true;
//		}
//
//		try {
//			IEditorInput input = fTextEditor.getEditorInput();
//			IResource resource =
//				(IResource) ((IAdaptable) input).getAdapter(IResource.class);
//
//			// Write output file
//			FileOutputStream fos = new FileOutputStream(new File(tmpFileName));
//			fos.write(text.getBytes());
//			fos.flush();
//			fos.close();
//
//			proc =
//				Runtime.getRuntime().exec(
//					PerlEditorPlugin
//						.getDefault()
//						.getExecutablePreference()
//						.trim()
//						+ " "
//						+ "-I"
//						+ ((IFileEditorInput) this.fTextEditor.getEditorInput())
//							.getFile()
//							.getLocation()
//							.makeAbsolute()
//							.removeLastSegments(1)
//						+ " "
//						+ PERL_CMD_EXT
//						+ " "
//						+ tmpFileName);
//
//			InputStream in = proc.getErrorStream();
//
//			StringBuffer content = new StringBuffer();
//
//			byte[] buffer = new byte[1];
//
//			int read;
//			while ((read = in.read(buffer)) > 0) {
//				content.append(new String(buffer));
//			}
//			in.close();
//
//			//jjjjjjj
//			// DEBUG start
//			System.out.println("-----------------------------------------");
//			System.out.println("           OUTPUT");
//			System.out.println("-----------------------------------------");
//			System.out.println(content);
//			System.out.println("-----------------------------------------");
//			// DEBUG END
//
//			String line = null;
//			List lines = new ArrayList();
//			int index;
//
//			// Compare checksums
//			int hashCode = content.toString().hashCode();
//
//			if (previousHashCode == hashCode) {
//
//				return true;
//			}
//
//			previousHashCode = hashCode;
//
//			StringTokenizer st = new StringTokenizer(content.toString(), "\n");
//
//			int lineCount = 0;
//
//			while (st.hasMoreTokens()) {
//				line = st.nextToken();
//				if (line.indexOf("\r") != -1) {
//					line = line.substring(0, line.indexOf("\r"));
//				}
//
//				lines.add(line);
//				if (++lineCount >= maxErrorsShown) {
//					break;
//				}
//
//			}
//
//			//Delete markers
//			resource.deleteMarkers(IMarker.PROBLEM, true, 1);
//
//			// Markers have to be added in reverse order
//			// Otherwise lower line number will appear at the end of the list
//			for (int i = lines.size() - 1; i >= 0; i--) {
//				line = (String) lines.get(i);
//
//				// If error message is not from temporary file, skip
//				if (line.indexOf(tmpFileName) == -1) {
//					continue;
//				}
//
//				// Delete filename from error message
//				StringBuffer lineSb = new StringBuffer(line);
//				replace(lineSb, tmpFileName + " ", "", true);
//				line = lineSb.toString();
//
//				if ((index = line.indexOf(PERL_ERROR_INDICATOR)) != -1) {
//
//					// truncatedLIne is the stripped error-line up to the next " " after the line number if present
//					// To avoid cluttering with other "." and "," which might occur in the error message
//					String truncatedLine = line;
//					if (truncatedLine
//						.indexOf(" ", index + PERL_ERROR_INDICATOR.length() + 1)
//						!= -1) {
//						truncatedLine =
//							truncatedLine.substring(
//								0,
//								truncatedLine.indexOf(
//									" ",
//									index + PERL_ERROR_INDICATOR.length() + 1));
//					}
//
//					int endIndex;
//					if ((endIndex = truncatedLine.indexOf(".", index)) == -1) {
//						endIndex = truncatedLine.indexOf(",", index);
//					}
//
//					if (endIndex == -1) {
//						continue;
//					}
//
//					String lineNr =
//						truncatedLine.substring(
//							index + PERL_ERROR_INDICATOR.length(),
//							endIndex);
//
//					// If there is an addition to the error message
//					if (i + 1 < lines.size()) {
//						if (((String) lines.get(i + 1)).startsWith(" ")) {
//							line += " " + (String) lines.get(i + 1);
//						}
//					}
//
//					IMarker marker = resource.createMarker(IMarker.PROBLEM);
//
//					// Check if it's a warning
//					boolean isWarning = false;
//
//					for (int x = 0; x < WARNING_STRINGS.length; x++) {
//						if (truncatedLine.indexOf(WARNING_STRINGS[x]) != -1) {
//							isWarning = true;
//						}
//					}
//
//					if (isWarning) {
//						marker.setAttribute(
//							IMarker.SEVERITY,
//							IMarker.SEVERITY_WARNING);
//					} else {
//						marker.setAttribute(
//							IMarker.SEVERITY,
//							IMarker.SEVERITY_ERROR);
//					}
//
//					marker.setAttribute(IMarker.MESSAGE, line);
//
//					marker.setAttribute(
//						IMarker.LINE_NUMBER,
//						Integer.parseInt(lineNr));
//
//					Position pos =
//						new Position(
//							fSourceViewer.getDocument().getLineOffset(
//								Integer.parseInt(lineNr) - 1));
//					fSourceViewer.getAnnotationModel().addAnnotation(
//						new MarkerAnnotation(marker),
//						pos);
//
//				}
//			}
//
//		} catch (Exception e) {
//			e.printStackTrace();
//			if (proc != null) {
//				killProcess(proc);
//			}
//			return false;
//		} finally {
//			try {
//				//				Delete tmp file
//				new File(tmpFileName).delete();
//			} catch (Exception ex) {
//				ex.printStackTrace();
//			}
//		}

		return true;

	}

  /**
    * Finds the file that's currently opened in the PHP Text Editor
    */
   protected IFile getPHPFile(IEditorInput editorInput) {
     if (editorInput instanceof IFileEditorInput)
       return ((IFileEditorInput) editorInput).getFile();

     return null;
   }
    
   protected void parse(IFile fileToParse, InputStream iStream) {

     StringBuffer buf = new StringBuffer();
     int c0;
     try {
       while ((c0 = iStream.read()) != (-1)) {
         buf.append((char) c0);
       }
     } catch (IOException e) {
       return;
     }
     String input = buf.toString();

     PHPParserSuperclass parser = PHPParserManager.getParser(fileToParse);
     try {
       parser.parse(input);
     } catch (CoreException e) {
     }
   }
   
	private void killProcess(Process proc) {
		while (true) {
			try {
				proc.destroy();
				proc.exitValue();
			} catch (Exception ex) {

				continue;
			}
			break;
		}
	}

	// Replaces all instances of the String o with the String n in the
	// StringBuffer orig if all is true, or only the first instance if all is false.
	private static void replace(
		StringBuffer orig,
		String o,
		String n,
		boolean all) {
		if (orig == null || o == null || o.length() == 0 || n == null)
			throw new IllegalArgumentException("Null or zero-length String");

		int i = 0;

		while (i + o.length() <= orig.length()) {
			if (orig.substring(i, i + o.length()).equals(o)) {
				orig.replace(i, i + o.length(), n);
				if (!all)
					break;
				else
					i += n.length();
			} else
				i++;
		}
	}
}