package org.motechproject.nms.region.service.impl;

import org.motechproject.mds.query.QueryExecution;
import org.motechproject.mds.util.InstanceSecurityRestriction;
import org.motechproject.nms.region.domain.Circle;
import org.motechproject.nms.region.domain.District;
import org.motechproject.nms.region.domain.Language;
import org.motechproject.nms.region.domain.NationalDefaultLanguage;
import org.motechproject.nms.region.domain.State;
import org.motechproject.nms.region.repository.LanguageDataService;
import org.motechproject.nms.region.repository.NationalDefaultLanguageDataService;
import org.motechproject.nms.region.service.DistrictService;
import org.motechproject.nms.region.service.LanguageService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.jdo.Query;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

@Service("languageService")
public class LanguageServiceImpl implements LanguageService {
    public static final int NATIONAL_DEFAULT_CODE = 0;
    private LanguageDataService languageDataService;
    private NationalDefaultLanguageDataService nationalDefaultLanguageDataService;
    private DistrictService districtService;

    @Autowired
    public LanguageServiceImpl(LanguageDataService languageDataService,
                               NationalDefaultLanguageDataService nationalDefaultLanguageDataService,
                               DistrictService districtService) {
        this.languageDataService = languageDataService;
        this.nationalDefaultLanguageDataService = nationalDefaultLanguageDataService;
        this.districtService = districtService;
    }

    /**
     * Given a languageCode returns the object if one exists
     * @param code the code for the language record
     * @return The language Record if it exists
     */
    @Override
    public Language getForCode(String code) {
        return languageDataService.findByCode(code);
    }

    @Override
    public List<Language> getAllForCircle(final Circle circle) {

        // TODO: This query needs to join from circle -> State -> District
        QueryExecution<List<Language>> stateQueryExecution = new QueryExecution<List<Language>>() {
            @Override
            public List<Language> execute(Query query, InstanceSecurityRestriction restriction) {

                query.setFilter("circle == _circle && circle.state == _state && circle.state.district == _district");
                query.declareParameters("org.motechproject.nms.region.domain.Circle _circle, " +
                        "org.motechproject.nms.region.domain.State _state, " +
                        "org.motechproject.nms.region.domain.District _district");

                return (List<Language>) query.execute(circle);
            }
        };

        List<Language> languages = languageDataService.executeQuery(stateQueryExecution);

        if (languages == null) {
            languages = new ArrayList<>();
        }

        return languages;
    }

    @Override
    public List<Language> getAll() {
        List<Language> languages = languageDataService.retrieveAll();

        if (languages == null) {
            languages = new ArrayList<>();
        }

        return languages;
    }

    @Override
    public Language getNationalDefaultLanguage() {
        Language language = null;

        NationalDefaultLanguage nationalDefaultLanguage;
        nationalDefaultLanguage = nationalDefaultLanguageDataService.findByCode(NATIONAL_DEFAULT_CODE);

        if (nationalDefaultLanguage != null) {
            language = nationalDefaultLanguage.getLanguage();
        }

        return language;
    }

    @Override
    public Set<State> getAllStatesForLanguage(Language language) {
        Set<State> states = new HashSet<>();
        Set<District> districts = districtService.getAllForLanguage(language);

        for (District district: districts) {
            states.add(district.getState());
        }

        return states;
    }
}

@@ -80,16 +80,19 @@
 s.query.
+Sql
 QueryExe
@@ -103,71 +103,8 @@
 on;%0A
-import org.motechproject.mds.util.InstanceSecurityRestriction;%0A
 impo
@@ -2050,83 +2050,11 @@
     
-// TODO: This query needs to join from circle -%3E State -%3E District%0A        
+Sql
 Quer
@@ -2080,22 +2080,17 @@
 guage%3E%3E 
-stateQ
+q
 ueryExec
@@ -2101,16 +2101,19 @@
 n = new 
+Sql
 QueryExe
@@ -2135,24 +2135,25 @@
 guage%3E%3E() %7B%0A
+%0A
             
@@ -2185,302 +2185,419 @@
 lic 
-List%3CLanguage%3E execute(Query query, InstanceSecurityRestriction restriction) %7B%0A%0A                query.setFilter(%22circle == _circle && circle.state == _state && circle.state.district == _district%22);%0A                query.declareParameters(%22org.motechproject.nms.region.domain.Circle _circle, %22 +
+String getSqlQuery() %7B%0A                String query = %22select * %22 +%0A                        %22from nms_languages l %22 +%0A                        %22join nms_districts d on  d.language_id_oid = l.id %22 +%0A                        %22join nms_states s on d.state_id_oid = s.id %22 +%0A                        %22join flw_module_join_circles_states cxs on s.id = cxs.state_id and cxs.circle_id = ?%22;%0A%0A                return query;
 %0A   
@@ -2597,32 +2597,35 @@
 ry;%0A            
+%7D%0A%0A
             %22org
@@ -2624,147 +2624,123 @@
     
-%22org.motechproject.nms.region.domain.State _state, %22 +%0A                        %22org.motechproject.nms.region.domain.District _district%22
+@Override%0A            public List%3CLanguage%3E execute(Query query) %7B%0A                query.setClass(Language.class
 );%0A
-%0A
     
@@ -2795,16 +2795,24 @@
 e(circle
+.getId()
 );%0A     
@@ -2898,20 +2898,18 @@
 cute
+SQL
 Query(
-stateQ
+q
 uery

Switch from jdoql to a sql query. This stops errors in the UserController tests (although one still fails)