/*
 * Java_File_Save.bsh - a BeanShell macro for saving new java files.
 *
 * Copyright (C) 2004 Nicholas O'Leary nol@deferential.net
 * 
 * :mode=beanshell:tabSize=3:indentSize=3:maxLineLen=0:noTabs=true:
 * :indentOnTab=true:indentOnEnter=true:folding=explicit:collapseFolds=1:
 *
 * {{{ License
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with the jEdit program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 * }}}
 *
 * Notes:
 *  Only the first 250 lines of the buffer are scanned for a suitable
 *  class or interface declaration.
 *  
 * Changes:
 *  17-May-04: Only scans if the edit mode is either 'java' or the default mode
 *           : Ignores declarations that are in multiline comments
 *  08-Jun-04: If an infinite loop is hit (1000 iterations) in the comment
 *           : parsing, it now opens the default save dialog, rather than
 *           : just returning.
 * $Id: Java_File_Save.bsh 24163 2015-11-28 15:03:20Z kerik-sf $
 */

//Localization
final static String InfiniteLoopError = jEdit.getProperty("macro.rs.JavaFileSave.InfiniteLoop.error", "Infinite loop:");

// Check this is a new file
if (buffer.isNewFile() && buffer.getPath() != null)
{
   // Only look further if the mode is 'java', or still the default
   String buffer_mode = buffer.getMode().toString();
   if (buffer_mode.equals("java") || buffer_mode.equals(jEdit.getProperty("buffer.defaultMode","")))
   {
      String fullpath = buffer.getPath();
      VFS vfs = VFSManager.getVFSForPath(fullpath);
      // Split into constituent parts
      String path = vfs.getParentOfPath(fullpath);
      String name = vfs.getFileName(fullpath);
      
      // At most, check the first 250 lines - this sounds reasonable to me
      int maxLine = Math.min(buffer.getLineCount(),250);
      import java.util.regex.Pattern;
      import java.util.regex.Matcher;
      // Build the regex - based on the offical java language spec.
      Pattern regex = Pattern.compile("^\\s*(public|protected|private|static|abstract|final|native|synchronized|transient|volatile|strictfp)?\\s*(class|interface)\\s*([^ {/]+).*");
      boolean inComment = false;
      for(int i=0;i<maxLine;i++)
      {
         String txt = buffer.getLineText(i);
         int count = 0;
			// See if this line has a the start or finish of a multiline comment
         while (txt.indexOf("/*")!=-1 || txt.indexOf("*/")!=-1)
			{
				// A little paranoia on my part 
            count++;
            if (count==1000)
            {
               Log.log(Log.ERROR,BeanShell.class,InfiniteLoopError+"["+txt+"]");
               buffer.save(view,null,true);
               return;
            }
				// Look for the next starting comment if we're not in a comment
            if (!inComment)
            {
               int commentStartIndex = txt.indexOf("/*");
               if (commentStartIndex != -1)
               {
                  inComment = true;
                  if (commentStartIndex+2 == txt.length())
                     txt = "";
                  else
                     txt = txt.substring(commentStartIndex+2);
               }
            }
				// Look for the next ending comment if we are in a comment
            if (inComment)
            {
               int commentEndIndex = txt.indexOf("*/");
               if (commentEndIndex != -1)
               {
                  inComment = false;
                  if (commentEndIndex+2 == txt.length())
                     txt = "";
                  else
                     txt = txt.substring(commentEndIndex+2);
               } else {
                  continue;
               }
            }
         }
			
			// We now know if the remainder of the line is in a comment or not
         if (!inComment)
         {
            Matcher matcher = regex.matcher(txt);
            if (matcher.matches())
            {
               // Extract the class/interface name
               name = matcher.group(3)+".java";
               break;
            }
         }
      }
      
      // Open the VFSBrowser
      String[] files = GUIUtilities.showVFSFileDialog(view,path+name,
                                                VFSBrowser.SAVE_DIALOG,false);
      if(files == null)
         return false;
      buffer.save(view,files[0],true);
      return;
   }
}

// This isn't a file that has been scanned, so just do a normal save
buffer.save(view,null,true);

/*

Macro index data (in DocBook format)

   <listitem>
      <para><filename>Java_File_Save.bsh</filename></para>
      <abstract><para>Acts as a wrapper script to the Save As action. If the buffer
      is a new file, it scans the first 250 lines for a Java class or interface
      declaration. On finding one, it extracts the appropriate filename to be
      used in the Save As dialog.</para></abstract>   
      </listitem>

*/
