-- objectAttacher

objectAttacher = {};

function objectAttacher.prerequisitesPresent(specializations)
    return SpecializationUtil.hasSpecialization(Attachable, specializations);
end;

function objectAttacher:load(savegame)
    self.searchBales = objectAttacher.searchBales;
    self.attachobjects = objectAttacher.attachobjects;
    self.detachobjects = objectAttacher.detachobjects;
    self.OrientJoint = objectAttacher.OrientJoint;
    self.setWorkState= SpecializationUtil.callSpecializationsFunction("setWorkState");
    self.isBaleInRange = objectAttacher.isBaleInRange;
    self.place = {};
    self.place.node1 = Utils.indexToObject(self.components, getXMLString(self.xmlFile,"vehicle.objectAttache#castPoint1"));        
    self.place.node2 = Utils.indexToObject(self.components, getXMLString(self.xmlFile,"vehicle.objectAttache#castPoint2"));
    self.place.attacherNode = Utils.indexToObject(self.components, Utils.getNoNil(getXMLString(self.xmlFile,"vehicle.objectAttache#attacherNode"),"0>"));
    self.place.highOffset = Utils.getNoNil(getXMLFloat(self.xmlFile,"vehicle.objectAttache#highOffset"),4);    
    self.Attachedobjects = {};
    self.attacherMod = 0;
    self.attacherModOld = 0;
    self.allowAttachment = true;
    self.balesAttached = false;
    self.attachBales = false;

end;
function objectAttacher:readStream(streamId, connection)
    self:setWorkState(streamReadBool(streamId), true);
end;

function objectAttacher:writeStream(streamId, connection)
    streamWriteBool(streamId, self.balesAttached);
end;
function objectAttacher:update(dt)
    if self:getIsActiveForInput() then
        if InputBinding.hasEvent(InputBinding.IMPLEMENT_EXTRA2) then
            self:setWorkState(not self.attachBales);
        end;
    end;
end;

function objectAttacher:updateTick(dt)
end;

function objectAttacher:draw()
    if self.balesAttached then
        g_currentMission:addHelpButtonText(string.format(g_i18n:getText("Unlock"), self.typeDesc), InputBinding.IMPLEMENT_EXTRA2);
    else
        g_currentMission:addHelpButtonText(string.format(g_i18n:getText("Lock"), self.typeDesc), InputBinding.IMPLEMENT_EXTRA2);
    end;

end;
function objectAttacher:isBaleInRange(node1,node2,Yoffset,Bale)
    local Xmax, Ymax, Zmax = getWorldTranslation(node1);
          Xmax, Ymax, Zmax = worldToLocal(self.place.attacherNode,Xmax, Ymax, Zmax);
          
    local Xmin, Ymin, Zmin = getWorldTranslation(node2);    
          Xmin, Ymin, Zmin = worldToLocal(self.place.attacherNode,Xmin, Ymin, Zmin);
    
    local Xt, Yt, Zt = getWorldTranslation(Bale);
          Xt, Yt, Zt = worldToLocal(self.place.attacherNode,Xt, Yt, Zt);
        
    if (Xt < math.max(Xmax,Xmin) and Xt > math.min(Xmax,Xmin)) and (Zt < math.max(Zmax,Zmin) and Zt > math.min(Zmax,Zmin)) and (Yt<= ((Ymax+Ymin)/2)+Yoffset and Yt>= (Ymax+Ymin)/2) then
        return true;
    else
        return false;
    end;
end;
function objectAttacher:searchBales()
    for index,item in pairs(g_currentMission.itemsToSave) do
        if item.item:isa(Bale) then 

            if item.item.isAttached == nil then--and (getUserAttribute(item.item.nodeId, "isHaybale") == true or getUserAttribute(item.item.nodeId, "isStrawbale") == true or getUserAttribute(item.item.nodeId, "isRoundbale") == true) then

                local isInRange = self:isBaleInRange(self.place.node1,self.place.node2,self.place.highOffset,item.item.nodeId);            

                local is1stAttached = false;
                if isInRange then
                    is1stAttached = self:attachobjects(item.item.nodeId,item.item);
                end;
                if is1stAttached then
                    self.balesAttached = true;
                end;
            end;
        end;
    end;
    for k,v in pairs(g_currentMission.vehicles) do
        if v ~= self and v ~= self.attacherVehicle then
            local is1stAttached = false;
            for index,components in pairs(v.components) do        
                local isInRange = self:isBaleInRange(self.place.node1,self.place.node2,self.place.highOffset,components.node);    
                if isInRange then    
                    is1stAttached = self:attachobjects(components.node);
                end;
            end;
            if is1stAttached then
                self.balesAttached = true;
            end;
        end;
    end;
end;
function objectAttacher:setWorkState(isCoupling,noEventSend)
    WorkStateEvent.sendEvent(self, isCoupling, noEventSend);
    if isCoupling then
        self:detachobjects();
        self.attachBales = true;
    else
        self:searchBales();
        self.attachBales = false;
    end;

end;
function objectAttacher:OrientJoint(Source, Target)    
    local xw, yw, zw = getWorldTranslation(Source);        
    local x,y,z = worldToLocal(getParent(Target), xw, yw, zw);    
    setTranslation(Target, x,y,z);            
    --JointRotation Anpassung an das Objekt
    local zX, zY, zZ = localDirectionToWorld(Source, 0,0,1);
    local zX, zY, zZ = worldDirectionToLocal(getParent(Target), zX, zY, zZ);
    local yX, yY, yZ = localDirectionToWorld(Source, 0,1,0);
    local yX, yY, yZ = worldDirectionToLocal(getParent(Target), yX, yY, yZ);
    setDirection(Target, zX, zY, zZ, yX, yY, yZ);
    return false;
end;

function objectAttacher:attachobjects(object,baleT)
    local attachedobject = {};
    attachedobject.object = object;
    if self.isServer then
        attachedobject.AT = createTransformGroup("AT");
        link(self.place.attacherNode,attachedobject.AT);
        
        attachedobject.objectMass = getMass(object);
        setMass(object,attachedobject.objectMass*0.3);
        
        self:OrientJoint(object,attachedobject.AT);

        local constr = JointConstructor:new();                    
        constr:setActors(self.place.attacherNode, object);
        constr:setJointTransforms(attachedobject.AT,  object);
        for i=1, 3 do
            constr:setTranslationLimit(i-1, true, 0, 0);
            constr:setRotationLimit(i-1,0,0);
        end;
        attachedobject.JointIndex = constr:finalize();
        
        if baleT ~= nil then
            attachedobject.baleT = baleT;
            baleT.isAttached = true;
        end;
    end;

    table.insert(self.Attachedobjects, attachedobject);
    return true;
end;

function objectAttacher:detachobjects()
    if self.isServer then
        for k,v in pairs(self.Attachedobjects) do
            removeJoint(v.JointIndex);
            delete(v.AT);
            v.JointIndex = nil;
            setMass(v.object,v.objectMass);
            if v.baleT ~= nil then
                v.baleT.isAttached = nil;
            end;
        end;
    end;
    
    self.Attachedobjects = nil;
    self.Attachedobjects = {};
    self.balesAttached = false;
end;



function objectAttacher:onAttach(attacherVehicle)
    if self.isServer then
        self:setWorkState(false);
    end;
end;
function objectAttacher:onDetach()

    if self.isServer then
        self:setWorkState(true);
    end;
end;
function objectAttacher:onActivate()
    --if self.isServer then
        --self:setWorkState(false);
    --end;
end;
function objectAttacher:onDeactivate()
    --if self.isServer then
        --self:setWorkState(true);
    --end;
end;
function objectAttacher:loadFromAttributesAndNodes(savegame, key, resetVehicles)
    if not resetVehicles then

    end;
    return BaseMission.VEHICLE_LOAD_OK;
end;

function objectAttacher:getSaveAttributesAndNodes(nodeIdent)
   -- local attributes = ' side="'..tostring(self.currentSide)..'"';
    local attributes = nil;
    local node = nil;
    return attributes, node;
end;
function objectAttacher:delete()

end;

function objectAttacher:mouseEvent(posX, posY, isDown, isUp, button)
end;

function objectAttacher:keyEvent(unicode, sym, modifier, isDown)
end;
