function [out] = SpaceExToStateflow(varargin)
%SPACEEXTOSTATEFLOW SpaceEx to Stateflow conversion
%
% example call without semantics preservation:
% SpaceExToStateflow('mymodel.xml', 'myconfig.cfg', '--folder', 'myfolder')
% This uses SpaceEx model ..\examples\myfolder\mymodel.xml with myconfig.cfg.
%
% example call with semantics preservation: add '-s' like in the following:
% SpaceExToStateflow('mymodel.xml', 'myconfig.cfg', '--folder', 'myfolder', '-s')
%
% Actual calls on example systems:
%
% 1) Heater Lygeros system
% This model has nondeterminism, so to simulate all executions, we need to
% use the semantics preserving converter. The non-semantics preserving
% converter will work, but it will generate ONE of the infinitely many
% executions (all modulo numeric accuracy of course).
%
% SpaceExToStateflow('heaterLygeros.xml', 'heaterLygeros.cfg', '--folder', 'heaterLygeros') 
% 
% 2) Van Der Pol Oscillator (nonlinear example)
%
% SpaceExToStateflow('vanderpol.xml', 'vanderpol.cfg', '--folder', 'vanderpol')
%
% You can manually add an X-Y graph scope/plot and see that its phase
% portrait looks correct.
%
% ------------------------------------------------------------------------------
% author: Luan Viet Nguyen
% ------------------------------------------------------------------------------

    %Ex: how to instantiate java objects into Matlab
    %add java library for spaceex parsing library (from spaceex2boogie)
    javaaddpath(['lib', filesep, 'Hyst.jar']);
    % check if next works with: javaclasspath
    %javaaddpath(['..', filesep, 'lib', filesep, 'antlr-runtime-4.4.jar']);
    %javaaddpath(['..', filesep, 'lib', filesep, 'junit-4.11.jar']);
    %javaaddpath(['.', filesep, 'lib', filesep, 'spaceex-converter.jar']);
    import de.uni_freiburg.informatik.swt.spaceexboogieprinter.*;
    import com.verivital.hyst.automaton.*;
    import com.verivital.hyst.grammar.antlr.*;
    import com.verivital.hyst.grammar.formula.*;
    import com.verivital.hyst.grammar.formula.*;
    import com.verivital.hyst.importer.*;
    import com.verivital.hyst.junit.*;
    import com.verivital.hyst.main.*;
    import com.verivital.hyst.passes.*;
    import com.verivital.hyst.printers.*;
    import com.verivital.hyst.simulation.*;
    
    import de.uni_freiburg.informatik.swt.spaceexxmlprinter.*;
    import de.uni_freiburg.informatik.swt.spaxeexxmlreader.*;
    import de.uni_freiburg.informatik.swt.sxhybridautomaton.*;
    
    %
    % add classes and functions subfolders to path
    addpath(genpath('functions'));
    % Specify options from the input argument
    [opt_xml_reader, opt_cfg_reader, opt_semantics, opt_display_flow, ...
        opt_display_guard, opt_display_invariant, opt_randgen, ...
        opt_eager_violation, path_name, xml_filename, cfg_filename] = option_SpaceExToStateflow(varargin);
    xml_filepath = [path_name, xml_filename];
    cfg_filepath = [path_name, cfg_filename];
    % add option for using model without .cfg file
    if opt_xml_reader == 1
        try
        % read spaceex XML model file
            xml = xmlread(xml_filepath);  
            [pathstr,name,ext] = fileparts(xml_filepath);  
        catch exception
            %if ~exist('..\examples\xml_filename', 'file')
                disp('The xml file does not exist');
                throw(exception)
            %end 
        end
        if opt_cfg_reader == 1 
            try
                cfg_reader = java.io.FileReader(cfg_filepath);
                % create SpaceexDocuments
                % read both spaceex XML model and configuration files
                xml_cfg = de.uni_freiburg.informatik.swt.spaxeexxmlreader.SpaceExXMLReader(xml, cfg_reader);
                doc = xml_cfg.read();
            catch exception
               %if ~exist('..\examples\cfg_filename', 'file')
                    disp('The configuration file does not exist');
                    throw(exception);
               %end
            end
        else
            try
                xml_reader = de.uni_freiburg.informatik.swt.spaxeexxmlreader.SpaceExXMLReader(xml);
                %create SpaceexDocuments
                doc = xml_reader.read();
            catch exception
               throw(exception);
            end
        end  
    % create an error message if no xml file found
    else
        throw(MException('ResultChk:BadInput','Argument does not contain xml file, please input the xml file name'));
    end
    
    if opt_randgen == 1
    	output_path = ['.', filesep, 'output_SLSF', filesep];
    else
	output_path = ['.', filesep, 'output', filesep];
    end

    
    bdclose(name); % close model (uncoditionally, careful in case this is called and open diagrams are not saved!)
    
    % Reference: http://blogs.mathworks.com/seth/2010/01/21/building-models-with-matlab-code/
    % Reference: http://www.mathworks.com/help/stateflow/api/quick-start-for-the-stateflow-api.html
    rt = sfroot;
    m = rt.find('-isa','Simulink.BlockDiagram');
    % chart_ref = m.find('-isa','Stateflow.Chart');
    prev_models = rt.find('-isa','Simulink.BlockDiagram');
    % create new model, and get current models
    sfnew;
    curr_models = rt.find('-isa','Simulink.BlockDiagram');
    % new model is current models - previous models
    m = setdiff(curr_models, prev_models);
    % save model file
    %
    sfsave(m.Name, [output_path, name, '.mdl']);
    %
    % Get chart in new model
    ch = m.find('-isa', 'Stateflow.Chart');
    ch.Name = strcat('SF_',name);  
    % Update chart method type to be continuous
    ch.ChartUpdate='CONTINUOUS';
    % Import hybidautomaton into SLSF
    ha = com.verivital.hyst.importer.SpaceExImporter.flatten(doc);
    %modeName = ha.modes.keySet().toArray;
    %basecomponent
    if (opt_semantics)
        semanticTranslation(ch, ha, name, opt_eager_violation);
    else
        [sF] = Location_SpaceExToStateflow(m,ch,ha,name,opt_cfg_reader,opt_display_flow,opt_display_invariant);
        Transition_SpaceExToStateflow(sF,ch,ha,opt_display_guard);
    end
        % Constant test
        %
        % Pass all names of constant from SpaceEx into SF
% 
%         if (opt_semantics)
%             [constants] = semanticTranslation(ch, mode, ...
%                 doc.getInitialStateConditions(), name, opt_eager_violation);
%         else
%             % translate locations from SpaceEx into SF
%             [sF,variables,out_vars,idToLocation,initialConstants] = Location_SpaceExToStateflow(m,ch,mode,doc,name,opt_cfg_reader,opt_display_flow,opt_display_invariant);
%             % translate transitions from SpaceEx into SF
%             Transition_SpaceExToStateflow(sF,ch,mode,variables,out_vars,idToLocation,opt_display_guard);
%         end
% %         elseif isa(mode, 'NetworkComponent')
% %             boogiePrinter.setNetWork(mode);
% %             for i_bind = 0 : mode.getBindCount() - 1
% %                 binds(i_bind + 1) = mode.getBind(i_bind);
% %                 boogiePrinter.setBase(mbase);
% %                 boogiePrinter.setBind(mode.getBind(i_bind));
% %                 % Instantiate constantList object and acquire constant
% %                 % values from collectConstantsValue()method
% %                 constantList = boogiePrinter.getConstants();
% %                 boogiePrinter.collectConstantsValue();
% %                 % transfer constant values from SpaceEx into SF
% % 
% %                 if (opt_semantics)
% %                     if (~ (exist('constants', 'var')))
% %                         constants = cell(0, 2);
% %                     end
% %                     % transfer constant values from SpaceEx into SF
% %                     [constants] = ...
% %                         semanticTranslationNetwork(constantList, constants);
% %                 else
% %                     [constantNames] = getConstantValues_SpaceExToStateflow(m,ch,constantList,initialConstants);
% %                 end
% %             end
% %         else
% %             assert(false, 'unknown component type');
% %         end
%     end
    
    % Save model file
    %
    if opt_randgen == 1
        output_path_randgen = ['.', filesep, 'output_SLSF', filesep];
        delete(['.', filesep, 'output', filesep,name,'.mdl']);
        sfsave(m.Name, [output_path_randgen, name, '.mdl']);
    else
        sfsave(m.Name, [output_path, name, '.mdl']);
    end
    %
    
    out = ha;
end
