package com.siberika.idea.pascal.sdk;
import com.intellij.codeInspection.SmartHashMap;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.projectRoots.Sdk;
import com.intellij.openapi.projectRoots.SdkAdditionalData;
import com.intellij.openapi.projectRoots.SdkModificator;
import com.intellij.openapi.projectRoots.SdkType;
import com.intellij.openapi.projectRoots.SdkTypeId;
import com.siberika.idea.pascal.jps.sdk.PascalCompilerFamily;
import com.siberika.idea.pascal.jps.sdk.PascalSdkData;
import com.siberika.idea.pascal.util.StrUtil;
import com.siberika.idea.pascal.util.SysUtils;
import org.apache.commons.lang.StringUtils;
import org.jdom.Element;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.io.File;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;
/**
* Author: George Bakhtadze
* Date: 10/01/2013
*/
public abstract class BasePascalSdkType extends SdkType {
private static final Logger LOG = Logger.getInstance(BasePascalSdkType.class.getName());
private static final String[] EMPTY_ARGS = new String[0];
private final String compilerFamily;
private Map<String, Map<String, Directive>> directives;
private Map<String, Map<String, Define>> defines;
protected BasePascalSdkType(@NonNls String name, @NonNls PascalCompilerFamily compilerFamily) {
super(name);
this.compilerFamily = compilerFamily.name();
}
@NotNull
public static PascalSdkData getAdditionalData(@NotNull Sdk sdk) {
SdkAdditionalData params = sdk.getSdkAdditionalData();
if (!(params instanceof PascalSdkData)) {
params = new PascalSdkData();
SdkModificator sdkModificator = sdk.getSdkModificator();
sdkModificator.setSdkAdditionalData(params);
sdkModificator.commitChanges();
}
return (PascalSdkData) params;
}
public static File getDecompilerCommand(@NotNull Sdk sdk, File defaultDecompilerCommand) {
File res;
String command = (String) getAdditionalData(sdk).getValue(PascalSdkData.Keys.DECOMPILER_COMMAND.getKey());
if (StringUtils.isEmpty(command)) {
res = defaultDecompilerCommand;
} else {
res = new File(command);
}
if (!res.canExecute()) {
LOG.info("ERROR: Invalid decompiler command: " + command);
}
return res;
}
public static String getDebuggerCommand(@Nullable Sdk sdk, String defaultDebuggerCommand) {
String command = sdk != null ? (String) getAdditionalData(sdk).getValue(PascalSdkData.Keys.DEBUGGER_COMMAND.getKey()) : null;
if (StringUtils.isEmpty(command)) {
return defaultDebuggerCommand;
} else {
return command;
}
}
public static String[] getDecompilerArgs(Sdk sdk) {
return EMPTY_ARGS;
/*String command = (String) getAdditionalData(sdk).getValue(PascalSdkData.DATA_KEY_DECOMPILER_COMMAND);
if (StringUtils.isEmpty(command) || !command.contains(" ")) {
return EMPTY_ARGS;
}
return command.substring(command.indexOf(" ")+1).split(" ");*/
}
/**
* Retrieves compiler defines from compiler command line parameters specified in SDK options
* @param defines collection of defines to append defines to
* @param options command line specified in SDK
*/
public static void getDefinesFromCmdLine(Map<String, Define> defines, @Nullable String options) {
if (null == options) {
return;
}
String[] compilerOptions = options.split("\\s+");
for (String opt : compilerOptions) {
if (opt.startsWith("-d")) {
defines.put(opt.substring(2).toUpperCase(), new Define(opt.substring(2), null, 0));
}
}
}
public static Map<String, Define> getDefaultDefines(@NotNull Sdk sdk, String version) {
SdkTypeId id = sdk.getSdkType();
if (id instanceof BasePascalSdkType) {
SdkAdditionalData data = sdk.getSdkAdditionalData();
Map<String, Define> result = new HashMap<String, Define>();
if (data instanceof PascalSdkData) {
String options = (String) ((PascalSdkData) data).getValue(PascalSdkData.Keys.COMPILER_OPTIONS.getKey());
getDefinesFromCmdLine(result, options);
}
Map<String, Map<String, Define>> compilerDefines = ((BasePascalSdkType) id).defines;
for (Map.Entry<String, Map<String, Define>> entry : compilerDefines.entrySet()) {
if (StrUtil.isVersionLessOrEqual(entry.getKey(), version)) {
result.putAll(entry.getValue());
}
}
return result;
}
return new SmartHashMap<String, Define>();
}
public static Map<String, Directive> getDirectives(@NotNull Sdk sdk, String version) {
SdkTypeId id = sdk.getSdkType();
if (id instanceof BasePascalSdkType) {
Map<String, Map<String, Directive>> directives = ((BasePascalSdkType) id).directives;
Map<String, Directive> result = new HashMap<String, Directive>();
for (Map.Entry<String, Map<String, Directive>> entry : directives.entrySet()) {
if (StrUtil.isVersionLessOrEqual(entry.getKey(), version)) {
result.putAll(entry.getValue());
}
}
return result;
}
return new SmartHashMap<String, Directive>();
}
protected void configureOptions(@NotNull Sdk sdk, PascalSdkData data, String target) {
}
@Override
public void saveAdditionalData(@NotNull final SdkAdditionalData additionalData, @NotNull final Element additional) {
if (additionalData instanceof PascalSdkData) {
for (PascalSdkData.Keys key : PascalSdkData.Keys.values()) {
Object val = ((PascalSdkData)additionalData).getValue(key.getKey());
if (val instanceof String) {
additional.setAttribute(key.getKey(), val != null ? (String) val : "");
}
}
additional.setAttribute(PascalSdkData.Keys.COMPILER_FAMILY.getKey(), compilerFamily);
}
}
@Nullable
@Override
public SdkAdditionalData loadAdditionalData(Element additional) {
PascalSdkData result = new PascalSdkData();
if (additional != null) {
for (PascalSdkData.Keys key : PascalSdkData.Keys.values()) {
result.setValue(key.getKey(), additional.getAttributeValue(key.getKey()));
}
result.setValue(PascalSdkData.Keys.COMPILER_FAMILY.getKey(), compilerFamily);
}
return result;
}
void loadResources(String resourcePrefix) {
InputStream definesStream = null;
InputStream directivesStream = null;
try {
definesStream = getClass().getResourceAsStream("/" + resourcePrefix + "Defines.xml");
if (definesStream != null) {
defines = DefinesParser.parse(definesStream);
}
directivesStream = getClass().getResourceAsStream("/" + resourcePrefix + "Directives.xml");
if (directivesStream != null) {
directives = DirectivesParser.parse(directivesStream);
}
} finally {
SysUtils.close(definesStream);
SysUtils.close(directivesStream);
}
}
}