package org.semanticsoft.vaaclipse.theme;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.semanticsoft.vaaclipse.publicapi.theme.Theme;
import org.semanticsoft.vaaclipse.publicapi.theme.ThemeContribution;
public class ThemeImpl extends ThemeEntryImpl implements Theme {
private String label;
private String description;
private List<ThemeContribution> contributions = new ArrayList<ThemeContribution>();
private List<Theme> inheritedThemes = new ArrayList<Theme>();
private List<String> cssCashList;
private List<String> resourcesCashList;
private byte[] cssBytes;
public ThemeImpl(String id, String label)
{
super(id);
this.label = label;
}
public void setId(String id)
{
this.id = id;
}
public String getLabel() {
return label;
}
@Override
public String getDescription()
{
return this.description;
}
public void setDescription(String description)
{
this.description = description;
}
@Override
public List<Theme> getInheritedThemes()
{
return Collections.unmodifiableList(this.inheritedThemes);
}
@Override
public List<ThemeContribution> getContributions()
{
return Collections.unmodifiableList(this.contributions);
}
public void addContribution(ThemeContribution contibution)
{
this.resourcesCashList = null;
this.cssCashList = null;
this.contributions.add(contibution);
}
public void addInheritedTheme(Theme theme)
{
this.resourcesCashList = null;
this.cssCashList = null;
this.inheritedThemes.add(theme);
}
@Override
public String toString() {
return "Theme [id=" + id + ", label='" + label;
}
@Override
public List<String> getAllCssURIs()
{
if (cssCashList == null)
{
cssCashList = new ArrayList<String>();
cssCashList.add(getCssUri());
for (Theme theme : this.getInheritedThemes())
{
cssCashList.addAll(theme.getAllCssURIs());
}
for (ThemeContribution c : this.getContributions())
{
if (c.getCssUri() != null)
cssCashList.add(c.getCssUri());
}
}
return cssCashList;
}
@Override
public List<String> getAllResourceLocationURIs()
{
if (resourcesCashList == null)
{
resourcesCashList = new ArrayList<String>();
resourcesCashList.addAll(getResourceLocationURIs());
for (Theme theme : this.getInheritedThemes())
{
resourcesCashList.addAll(theme.getAllResourceLocationURIs());
}
for (ThemeContribution c : this.getContributions())
{
resourcesCashList.addAll(c.getResourceLocationURIs());
}
}
return Collections.unmodifiableList(resourcesCashList);
}
@Override
public InputStream getCssAsStream()
{
return new ByteArrayInputStream(cssBytes);
}
@Override
public InputStream getThemeResourceAsStream(String themeUri)
{
InputStream in = null;
for (String resLocUri : getAllResourceLocationURIs())
{
String bundlePath = resLocUri + themeUri;
try {
URL u = new URL(bundlePath);
in = u.openStream();
break;
}
catch (Exception ex) {}
}
return in;
}
void prepareTheme() throws Exception
{
StringBuffer inheritedBuffer = new StringBuffer();
for (Theme inherited : inheritedThemes)
{
inheritedBuffer.append(String.format("@import \"../%s/styles.css\";", inherited.getWebId()));
}
List<ThemeContributionImpl> afterMainCss = new ArrayList<ThemeContributionImpl>();
List<ThemeContributionImpl> afterInheritedImports = new ArrayList<ThemeContributionImpl>();
List<ThemeContributionImpl> beforeInheritedImports = new ArrayList<ThemeContributionImpl>();
Map<String, List<ThemeContributionImpl>> bindedContributionsBefore = new HashMap<String, List<ThemeContributionImpl>>();
Map<String, List<ThemeContributionImpl>> bindedContributionsAfter = new HashMap<String, List<ThemeContributionImpl>>();
for (ThemeContribution c : this.contributions)
{
if (c.getCssUri() == null)
continue;
ThemeContributionImpl contribution = (ThemeContributionImpl) c;
String pos = contribution.getInsertPosition();
String[] split = pos.split("=");
if (split.length == 2)
{
String mod = split[0].trim();
if ("after".equals(mod) || "before".equals(mod))
{
String value = split[1].trim();
if (mod.equals("after") && ThemeContribution.MAIN_CSS.equals(value))
{
afterMainCss.add(contribution);
}
else if (mod.equals("after") && ThemeContribution.INHERITED_IMPORTS.equals(value) ||
mod.equals("before") && ThemeContribution.MAIN_CSS.equals(value))
{
afterInheritedImports.add(contribution);
}
else if (mod.equals("before") && ThemeContribution.INHERITED_IMPORTS.equals(value))
{
beforeInheritedImports.add(contribution);
}
else
{//value - is contribution id?
if (mod.equals("before"))
{
if (!bindedContributionsBefore.containsKey(value))
bindedContributionsBefore.put(value, new ArrayList<ThemeContributionImpl>());
bindedContributionsBefore.get(value).add(contribution);
}
else if (mod.equals("after"))
{
if (!bindedContributionsAfter.containsKey(value))
bindedContributionsAfter.put(value, new ArrayList<ThemeContributionImpl>());
bindedContributionsAfter.get(value).add(contribution);
}
}
}
}
}
StringBuffer afterMainCssContributionsBuffer = buildStringBuffer(afterMainCss, bindedContributionsBefore, bindedContributionsAfter);
StringBuffer afterInheritedImportsContributionsBuffer = buildStringBuffer(afterInheritedImports, bindedContributionsBefore, bindedContributionsAfter);
StringBuffer beforeInheritedImportsContributionsBuffer = buildStringBuffer(beforeInheritedImports, bindedContributionsBefore, bindedContributionsAfter);
String ls = System.lineSeparator();
String total = beforeInheritedImportsContributionsBuffer.toString() + ls + inheritedBuffer.toString() + ls +
afterInheritedImportsContributionsBuffer.toString() + ls + "@import \"original_styles.css\";" + ls + afterMainCssContributionsBuffer.toString() + ls;
cssBytes = total.getBytes("UTF-8");
for (Theme inherited : inheritedThemes)
{
if (inherited instanceof ThemeImpl)
{
((ThemeImpl)inherited).prepareTheme();
}
}
}
private StringBuffer buildStringBuffer(List<ThemeContributionImpl> list,
Map<String, List<ThemeContributionImpl>> bindedContributionsBefore, Map<String, List<ThemeContributionImpl>> bindedContributionsAfter)
{
StringBuffer buffer = new StringBuffer();
List<ThemeContributionImpl> result = buildList(list, bindedContributionsBefore, bindedContributionsAfter);
for (ThemeContributionImpl c : result)
{
buffer.append(String.format("@import \"%s.css\";", c.getWebId()));
}
return buffer;
}
private List<ThemeContributionImpl> buildList(List<ThemeContributionImpl> list,
Map<String, List<ThemeContributionImpl>> bindedContributionsBefore, Map<String, List<ThemeContributionImpl>> bindedContributionsAfter)
{
bindedContributionsBefore = new HashMap<String, List<ThemeContributionImpl>>(bindedContributionsBefore);
bindedContributionsAfter = new HashMap<String, List<ThemeContributionImpl>>(bindedContributionsAfter);
List<ThemeContributionImpl> accumulator = new ArrayList<ThemeContributionImpl>();
int restBefore, restAfter;
do
{
restBefore = bindedContributionsBefore.size() + bindedContributionsAfter.size();
for (ThemeContributionImpl c : list)
{
List<ThemeContributionImpl> bindedList = bindedContributionsBefore.remove(c.getId());
if (bindedList != null)
accumulator.addAll(bindedList);
accumulator.add(c);
bindedList = bindedContributionsAfter.remove(c.getId());
if (bindedList != null)
accumulator.addAll(bindedList);
}
restAfter = bindedContributionsBefore.size() + bindedContributionsAfter.size();
list = accumulator;
accumulator = new ArrayList<ThemeContributionImpl>();
}
while (restBefore != restAfter);
return list;
}
}