package org.fugazi.qls.ast;
import org.fugazi.ql.ast.form.form_data.QLFormDataStorage;
import org.fugazi.ql.ast.statement.Question;
import org.fugazi.ql.ast.type.Type;
import org.fugazi.qls.ast.question.QLSQuestion;
import org.fugazi.qls.ast.segment.Page;
import org.fugazi.qls.ast.segment.Section;
import org.fugazi.qls.ast.segment.Segment;
import org.fugazi.qls.ast.style.DefaultStyleDeclaration;
import org.fugazi.qls.ast.style.Style;
import org.fugazi.qls.ast.stylesheet.StyleSheet;
import org.fugazi.qls.ast.stylesheet.stylesheet_data.visitor.FullQLSFormVisitor;
import org.fugazi.qls.ast.widget.AbstractQLSWidget;
import org.fugazi.qls.ast.widget.widget_types.IWidgetType;
import org.fugazi.qls.ast.widget.widget_types.WidgetTypeToWidgetVisitor;
import java.util.HashMap;
import java.util.List;
public class DefaultStyleHandler extends FullQLSFormVisitor {
private Segment currentSegment;
private final QLFormDataStorage formDataStorage;
private final DefaultWidgetsFactory defaultWidgetsFactory = new DefaultWidgetsFactory();
private final WidgetTypeToWidgetVisitor widgetTypeToWidget = new WidgetTypeToWidgetVisitor();
// Static factory method instead of constructor
public static DefaultStyleHandler applyStylesToStyleSheet(
QLFormDataStorage _formDataStorage, StyleSheet _styleSheet)
{
return new DefaultStyleHandler(_formDataStorage, _styleSheet);
}
private DefaultStyleHandler(
QLFormDataStorage _formDataStorage, StyleSheet _styleSheet)
{
this.formDataStorage = _formDataStorage;
_styleSheet.accept(this);
}
public Void visitStyleSheet(StyleSheet _styleSheet){
List<Page> pages = _styleSheet.getPages();
for (Page page : pages) {
page.accept(this);
}
return null;
}
public Void visitPage(Page _page) {
// set current segment
this.currentSegment = _page;
for (Section section : _page.getSections()) {
section.accept(this);
}
return null;
}
public Void visitSection(Section _section) {
// currentSegment is the parent.
Segment previousSegment = this.currentSegment;
List<DefaultStyleDeclaration> parentSegmentDefaultStyles = previousSegment.getDefaultStyleDeclarations();
List<DefaultStyleDeclaration> currentSegmentDefaultStyles = _section.getDefaultStyleDeclarations();
this.inheritStyles(
parentSegmentDefaultStyles, currentSegmentDefaultStyles);
this.addDeclarationsFromParentToSegment(
_section, parentSegmentDefaultStyles, currentSegmentDefaultStyles);
for (QLSQuestion question : _section.getQuestions()) {
this.constructQuestion(question, currentSegmentDefaultStyles);
}
// visit sub sections.
for (Section subsection : _section.getSections()) {
subsection.accept(this);
}
// set the current segment
this.currentSegment = _section;
return null;
}
private void inheritStyles(
List<DefaultStyleDeclaration> _parentSegmentDefaultStyles,
List<DefaultStyleDeclaration> _derivedSegmentDefaultStyles)
{
for (DefaultStyleDeclaration baseDeclaration : _parentSegmentDefaultStyles) {
if (baseDeclaration.getStyle().isUndefined()) {
Style defaultStyleOfWidget = this.getDefaultStyleForWidgetType(baseDeclaration.getWidgetType());
baseDeclaration.setStyle(defaultStyleOfWidget);
} else {
this.inheriteStyleFromParent(
_derivedSegmentDefaultStyles, baseDeclaration);
}
}
}
private void inheriteStyleFromParent(
List<DefaultStyleDeclaration> _derivedSegmentDefaultStyles,
DefaultStyleDeclaration _baseDeclaration)
{
for (DefaultStyleDeclaration currentDeclaration : _derivedSegmentDefaultStyles) {
Type currentDeclarationType = currentDeclaration.getQuestionType();
Style currentDeclarationStyle = currentDeclaration.getStyle();
if (_baseDeclaration.getQuestionType().equals(currentDeclarationType)) {
currentDeclarationStyle.inheriteFromStyle(_baseDeclaration.getStyle());
}
}
}
private void addDeclarationsFromParentToSegment(
Segment _segment,
List<DefaultStyleDeclaration> _parentSegmentDefaultStyles,
List<DefaultStyleDeclaration> _derivedSegmentDefaultStyles)
{
for (DefaultStyleDeclaration baseDeclaration : _parentSegmentDefaultStyles) {
if (!_derivedSegmentDefaultStyles.contains(baseDeclaration)) {
_segment.addDefaultStyleDeclaration(baseDeclaration);
}
}
}
private void constructQuestion(
QLSQuestion _question, List<DefaultStyleDeclaration> _segmentDefaultStyles)
{
// The question does not exist in the QL Form, ignore (leave it as Undefined)
if (!isQLSQuestionExistsInForm(_question)) {
return;
}
// if there is no default style declaration
if (_segmentDefaultStyles.size() == 0) {
if (_question.getWidget().isUndefined()) {
this.setDefaultWidgetToQuestion(_question);
} else {
this.setDefaultStyleToWidget(_question.getWidget());
}
} else {
// if is undefined, set from declarations.
if (_question.getWidget().isUndefined()) {
this.setWidgetFromDeclaration(_question, _segmentDefaultStyles);
} else {
// else set style to the widget.
this.styleQuestionFormDeclarations(_question, _segmentDefaultStyles);
}
}
}
private void setWidgetToQuestion(QLSQuestion _question, DefaultStyleDeclaration _styleDeclr) {
Type questionType = getQLQuestionType(_question);
String questionLabel = getQLQuestionLabel(_question);
IWidgetType currentDeclarationWidgetType = _styleDeclr.getWidgetType();
AbstractQLSWidget currentDeclarationWidget
= currentDeclarationWidgetType.accept(this.widgetTypeToWidget);
// if the widget is undefined, set the default widget fot that type.
if (currentDeclarationWidget.isUndefined()) {
currentDeclarationWidget = getDefaultWidgetForType(questionType, questionLabel);
}
Style currentDeclarationStyle = _styleDeclr.getStyle();
// if the style is undefined, set the default style of that widget.
// otherwise set the right style.
if (currentDeclarationStyle.isUndefined()) {
currentDeclarationWidget.resetStyleToDefault();
currentDeclarationWidget.setLabel(questionLabel);
} else {
currentDeclarationWidget.applyStyle(currentDeclarationStyle);
}
// set widget to the question.
_question.setWidget(currentDeclarationWidget);
}
private void setWidgetFromDeclaration(
QLSQuestion _question,
List<DefaultStyleDeclaration> _segmentDefaultStyles)
{
boolean isSet = false;
for (DefaultStyleDeclaration currentDeclaration : _segmentDefaultStyles) {
Type questionType = this.getQLQuestionType(_question);
Type currentDeclarationType = currentDeclaration.getQuestionType();
// if there is a style declaration for the question's type
if (questionType.equals(currentDeclarationType)) {
this.setWidgetToQuestion(_question, currentDeclaration);
isSet = true;
break;
}
}
// if there is no default style declaration for this type, set defaults
if (!isSet) {
this.setDefaultWidgetToQuestion(_question);
}
}
private void styleQuestionFormDeclarations(
QLSQuestion _question, List<DefaultStyleDeclaration> _segmentDefaultStyles)
{
boolean isWidgetFoundInDeclaration = false;
for (DefaultStyleDeclaration currentDeclaration : _segmentDefaultStyles) {
// if the widget has been found in declarations, set the style.
if (_question.getWidget().getType().equals(currentDeclaration.getWidgetType())) {
this.setWidgetToQuestion(_question, currentDeclaration);
isWidgetFoundInDeclaration = true;
break;
}
}
// if not set default
if (!isWidgetFoundInDeclaration) {
this.setDefaultStyleToWidget(_question.getWidget());
}
}
/**
* Helper Functions.
*/
private Type getQLQuestionType(QLSQuestion _question) {
String questionIdName = _question.getIdName();
HashMap<String, Type> questionTypes = this.formDataStorage.getallQuestionTypes();
return questionTypes.get(questionIdName);
}
private String getQLQuestionLabel(QLSQuestion _question) {
List<Question> qlQuestions = this.formDataStorage.getAllQuestions();
for (Question qlQuestion : qlQuestions) {
if (qlQuestion.getIdName().equals(_question.getIdName())) {
return qlQuestion.getLabel();
}
}
return "";
}
private boolean isQLSQuestionExistsInForm(QLSQuestion _question) {
List<Question> qlQuestions = this.formDataStorage.getAllQuestions();
for (Question qlQuestion : qlQuestions) {
if (qlQuestion.getIdName().equals(_question.getIdName())) {
return true;
}
}
return false;
}
private Style getDefaultStyleForWidgetType(IWidgetType _widgetType) {
AbstractQLSWidget widget = _widgetType.accept(this.widgetTypeToWidget);
return widget.getDefaultStyle();
}
private void setDefaultWidgetToQuestion(QLSQuestion _question) {
Type questionType = this.getQLQuestionType(_question);
String questionLabel = this.getQLQuestionLabel(_question);
AbstractQLSWidget defaultWidget = getDefaultWidgetForType(questionType, questionLabel);
this.setDefaultStyleToWidget(defaultWidget);
_question.setWidget(defaultWidget);
}
private void setDefaultStyleToWidget(AbstractQLSWidget _widget) {
_widget.resetStyleToDefault();
}
private AbstractQLSWidget getDefaultWidgetForType(Type _questionType, String _questionLabel) {
return this.defaultWidgetsFactory.getDefaultWidget(_questionType, _questionLabel);
}
}