public with sharing class UserInProcessController {
    public List<ProcInfo> procRecords { get; set; }
    
    /*****************検索用******************/
    // メガネアイコンを出すため、Daily_Report__cのOwnerIdを利用する
    // Daily_Report__cは皆権限ありますから
    public Daily_Report__c dummyDr { get; set; }
    
    public String sobj { get; set; }
    public String proc { get; set; }
    public String actor { get; set; }
    public String stay { get; set; }
    public String limits { get; set; }
    
    public List<SelectOption> procOpts { get; private set; }      // プロセス一覧
    public List<SelectOption> sObjectOpts { get; private set; }   // SObject一覧
    public List<SelectOption> limitOpts { get; private set; }
    public List<SelectOption> stayNotOpts { get; private set; }
    
    private List<ProcessDefinition> pdList = new List<ProcessDefinition>();
    private Map<String, String> sobjNameMap = new Map<String, String>();
    
    private static Integer procLimit = 1000;
    
    public UserInProcessController() {
        //originActor = new Daily_Report__c();
        dummyDr = new Daily_Report__c();
        pdList = [select Id, TableEnumOrId, Name, DeveloperName from ProcessDefinition where State = 'Active'];
        
        procOpts = new List<SelectOption>();
        procOpts.add(new SelectOption('', '--无--'));
        Set<String> existSObjSet = new Set<String>();
        for (ProcessDefinition pd : pdList) {
            procOpts.add(new SelectOption(pd.DeveloperName, pd.Name));
            existSObjSet.add(pd.TableEnumOrId);
        }
        
        sObjectOpts = new List<SelectOption>();
        sObjectOpts.add(new SelectOption('', '--无--'));
        Map<String, Schema.SObjectType> smap = Schema.getGlobalDescribe();
        for (String objKey : smap.keySet()) {
            Schema.SObjectType sobj = smap.get(objKey);
            Schema.DescribeSObjectResult sr = sobj.getDescribe();
            if (existSObjSet.contains(sr.getName())) {
                sObjectOpts.add(new SelectOption(sr.getName(), sr.getLabel()));
                sobjNameMap.put(sr.getName(), sr.getLabel());
            }
        }
        
        limitOpts = new List<SelectOption>();
        limitOpts.add(new SelectOption('50','50'));
        limitOpts.add(new SelectOption('100','100'));
        limitOpts.add(new SelectOption('200','200'));
        limitOpts.add(new SelectOption('500','500'));
        limitOpts.add(new SelectOption('' + (procLimit + 1), '全部'));
        //limits = '50';
        
        stayNotOpts = new List<SelectOption>();
        stayNotOpts.add(new SelectOption('', '--无--'));
        stayNotOpts.add(new SelectOption('在职', '在职'));
        stayNotOpts.add(new SelectOption('已离职', '已离职'));
    }
    
    public void init() {
        sobj = ApexPages.currentPage().getParameters().get('s');
        proc = ApexPages.currentPage().getParameters().get('p');
        actor = ApexPages.currentPage().getParameters().get('a');
        stay = ApexPages.currentPage().getParameters().get('sn');
        limits = ApexPages.currentPage().getParameters().get('l');
        if (String.isBlank(limits) == true) {
            limits = '200';
        }
        if (String.isBlank(actor) == false) {
            dummyDr.Reporter__c = actor;
        }
        searchProcessInfo();
    }
    
    public void searchProcessInfo() {
        procRecords = new List<ProcInfo>();
        
        String soql = this.makeSoql(actor, sobj, proc);
        soql += ' order by CreatedDate desc limit ' + Integer.valueOf(limits);
        List<ProcessInstanceWorkitem> processList = Database.query(soql);
        
        // UserIdの配列、SOQLは直接Userの項目を取得できないので
        List<Id> usrIds = new List<Id>();
        for (ProcessInstanceWorkitem pi : processList) {
            usrIds.add(pi.ActorId);
        }
        
        Map<Id, User> userMap = new Map<Id, User>();
        for (User u : [select Id, post__c, Stay_or_not__c, Pregnant_Rest__c, IsActive from User where Id in :usrIds]) {
            // ユーザ指定なく、在职/离职条件がある場合、UserMapを絞り込む
            if (String.isBlank(actor) == true && String.isBlank(stay) == false) {
                if (u.Stay_or_not__c == stay) {
                    userMap.put(u.Id, u);
                }
            }
            // ユーザ指定すれば、在职/离职条件が意味ない
            else if (String.isBlank(actor) == false){
                if (u.Id == actor) {
                    userMap.put(u.Id, u);
                }
            }
            else {
                userMap.put(u.Id, u);
            }
        }
        
        // 画面上にだす配列を作成
        for (ProcessInstanceWorkitem pi : processList) {
            if (userMap.containsKey(pi.ActorId)) {
                procRecords.add(new ProcInfo(pi, userMap, sobjNameMap));
            }
        }
        
        if (procRecords.size() > procLimit) {
            ApexPages.addmessage(new ApexPages.message(ApexPages.severity.INFO, '数据超过' + procLimit + '件，只显示前' + procLimit + '件'));
        } else {
            ApexPages.addmessage(new ApexPages.message(ApexPages.severity.INFO, '取得 ' + procRecords.size()  + ' 条数据'));
        }
    }
    
    public void resetProcOpts() {
        procOpts = new List<SelectOption>();
        procOpts.add(new SelectOption('', '--无--'));
        Set<String> existSObjSet = new Set<String>();
        for (ProcessDefinition pd : pdList) {
            if (String.isBlank(sobj) == false && pd.TableEnumOrId == sobj) {
                procOpts.add(new SelectOption(pd.DeveloperName, pd.Name));
            }
            if (String.isBlank(sobj) == true) {
                procOpts.add(new SelectOption(pd.DeveloperName, pd.Name));
            }
        }
    }
    
    private String makeSoql(String aid, String sname, String pname) {
        String soql = 'select Id, ProcessInstanceId, ActorId, OriginalActorId,'
                    + ' ProcessInstance.ProcessDefinition.Name, ProcessInstance.ProcessDefinition.TableEnumOrId, Actor.Name, OriginalActor.Name,'
                    + ' ProcessInstance.TargetObjectId'
                    //+ ' Actor.Stay_or_not__c, Actor.Post__c, Actor.Pregnant_Rest__c'
                    + ' from ProcessInstanceWorkitem'
                    + ' where IsDeleted = false';
        if (String.isBlank(aid) == false) {
            soql += ' and ActorId = \'' + aid + '\'';
        }
        if (String.isBlank(sname) == false) {
            soql += ' and ProcessInstance.ProcessDefinition.TableEnumOrId = \'' + sname + '\'';
        }
        if (String.isBlank(pname) == false) {
            soql += ' and ProcessInstance.ProcessDefinition.DeveloperName = \'' + pname + '\'';
        }
        
        return soql;
    }
    
    class ProcInfo {
        public ProcessInstanceWorkitem rec { get; private set; }
        public String post { get; private set; }
        public String stayOrNot { get; private set; }
        public Boolean pregnantRest { get; private set; }
        public String sobjName { get; private set; }
        public String active { get; private set; }
        
        public ProcInfo(ProcessInstanceWorkitem record, Map<Id, User> userMap, Map<String, String> sobjNameMap) {
            rec = record;
            post = userMap.get(record.ActorId).Post__c;
            stayOrNot = userMap.get(record.ActorId).Stay_or_not__c;
            pregnantRest = userMap.get(record.ActorId).Pregnant_Rest__c;
            sobjName = sobjNameMap.get(record.ProcessInstance.ProcessDefinition.TableEnumOrId);
            if (userMap.get(record.ActorId).IsActive == true) {
                active = '有效';
            } else {
                active = '无效';
            }
        }
    }
}