package me.coley.recaf.parse.bytecode.parser;

import me.coley.recaf.parse.bytecode.ASTParseException;
import me.coley.recaf.parse.bytecode.AbstractParser;
import me.coley.recaf.parse.bytecode.ParseResult;
import me.coley.recaf.parse.bytecode.ast.DefinitionModifierAST;
import me.coley.recaf.parse.bytecode.ast.DescAST;
import me.coley.recaf.parse.bytecode.ast.FieldDefinitionAST;
import me.coley.recaf.parse.bytecode.ast.NameAST;
import me.coley.recaf.parse.bytecode.ast.RootAST;
import me.coley.recaf.util.AutoCompleteUtil;

import java.util.Collections;
import java.util.List;

/**
 * {@link FieldDefinitionAST} parser.
 *
 * @author Matt
 */
public class FieldDefinitionParser extends AbstractParser<FieldDefinitionAST> {
	private static final int DEFINE_LEN = "FIELD ".length();

	@Override
	public FieldDefinitionAST visit(int lineNo, String line) throws ASTParseException {
		try {
			String trim = line.trim();
			// Fetch the name first, even though it appears after the access modifiers
			String[] split = trim.split("\\s+");
			if(split.length < 2)
				throw new ASTParseException(lineNo, "Bad format for FIELD, missing arguments");
			String name = split[split.length - 1];
			String desc =  split[split.length - 2];
			int nameStart = trim.lastIndexOf(name);
			int descStart = trim.lastIndexOf(" " + desc);
			int start = line.indexOf(trim);
			NameParser nameParser = new NameParser(this);
			nameParser.setOffset(nameStart);
			NameAST nameAST = nameParser.visit(lineNo, name);
			DescParser descParser = new DescParser();
			descParser.setOffset(descStart);
			DescAST descAST = descParser.visit(lineNo, desc);
			FieldDefinitionAST def = new FieldDefinitionAST(lineNo, start, nameAST, descAST);
			def.addChild(nameAST);
			// Parse access modifiers
			String modifiersSection = trim.substring(DEFINE_LEN, descStart);
			while(!modifiersSection.trim().isEmpty()) {
				// Get current modifier
				start = line.indexOf(modifiersSection);
				int space = modifiersSection.indexOf(' ');
				int end = space;
				if (end == -1)
					end = modifiersSection.length();
				String modStr = modifiersSection.substring(0, end);
				// Parse modifier
				ModifierParser modifierParser = new ModifierParser();
				modifierParser.setOffset(start);
				DefinitionModifierAST modifierAST = modifierParser.visit(lineNo, modStr);
				def.addModifier(modifierAST);
				// cut section to fit next modifier
				if (space == -1)
					break;
				else
					modifiersSection = modifiersSection.substring(modStr.length()).trim();
			}
			def.addChild(descAST);
			return def;
		} catch(IndexOutOfBoundsException ex) {
			throw new ASTParseException(ex, lineNo, "Bad format for FIELD");
		}
	}

	@Override
	public List<String> suggest(ParseResult<RootAST> lastParse, String text) {
		// If we have a space (after the FIELD part) and have not started writing the descriptor
		// then we can suggest access modifiers or the type
		if (text.contains(" ") && !text.contains(";")) {
			String[] parts = text.split("\\s+");
			String last = parts[parts.length - 1];
			if(last.charAt(0) == 'L') {
				// Complete type
				return AutoCompleteUtil.descriptorName(last);
			} else {
				// Complete modifier
				return new ModifierParser().suggest(lastParse, last);
			}
		}
		return Collections.emptyList();
	}
}

@@ -1754,32 +1754,66 @@
 ccess modifiers%0A
+%09%09%09if (descStart %3E DEFINE_LEN) %7B%0A%09
 %09%09%09String modifi
@@ -1867,16 +1867,17 @@
 rt);%0A%09%09%09
+%09
 while(!m
@@ -1908,24 +1908,25 @@
 sEmpty()) %7B%0A
+%09
 %09%09%09%09// Get c
@@ -1945,16 +1945,17 @@
 ier%0A%09%09%09%09
+%09
 start = 
@@ -1986,16 +1986,17 @@
 ction);%0A
+%09
 %09%09%09%09int 
@@ -2034,24 +2034,25 @@
 f(' ');%0A%09%09%09%09
+%09
 int end = sp
@@ -2060,19 +2060,19 @@
 ce;%0A%09%09%09%09
+%09
 if
- 
 (end == 
@@ -2071,24 +2071,25 @@
 (end == -1)%0A
+%09
 %09%09%09%09%09end = m
@@ -2114,24 +2114,25 @@
 ngth();%0A%09%09%09%09
+%09
 String modSt
@@ -2175,16 +2175,17 @@
 d);%0A%09%09%09%09
+%09
 // Parse
@@ -2190,24 +2190,25 @@
 se modifier%0A
+%09
 %09%09%09%09Modifier
@@ -2253,24 +2253,25 @@
 rser();%0A%09%09%09%09
+%09
 modifierPars
@@ -2287,24 +2287,25 @@
 set(start);%0A
+%09
 %09%09%09%09Definiti
@@ -2374,16 +2374,17 @@
 r);%0A%09%09%09%09
+%09
 def.addM
@@ -2405,16 +2405,17 @@
 erAST);%0A
+%09
 %09%09%09%09// c
@@ -2450,19 +2450,19 @@
 ier%0A%09%09%09%09
+%09
 if
- 
 (space =
@@ -2476,15 +2476,17 @@
 %09%09%09%09
+%09
 break;%0A
+%09
 %09%09%09%09
@@ -2491,24 +2491,25 @@
 %09%09else%0A%09%09%09%09%09
+%09
 modifiersSec
@@ -2567,16 +2567,22 @@
 trim();%0A
+%09%09%09%09%7D%0A
 %09%09%09%7D%0A%09%09%09

Fix modifier handling of fields