describe('iD.osmIsSimpleMultipolygonOuterMember', function() {
    it('returns the parent relation of a simple multipolygon outer', function() {
        var outer = iD.Way({tags: {'natural':'wood'}}),
            relation = iD.Relation({tags: {type: 'multipolygon'},
                members: [{id: outer.id, role: 'outer'}]}),
            graph = iD.Graph([outer, relation]);
        expect(iD.osmIsSimpleMultipolygonOuterMember(outer, graph)).to.equal(relation);
    });

    it('returns the parent relation of a simple multipolygon outer, assuming role outer if unspecified', function() {
        var outer = iD.Way({tags: {'natural':'wood'}}),
            relation = iD.Relation({tags: {type: 'multipolygon'},
                members: [{id: outer.id}]}),
            graph = iD.Graph([outer, relation]);
        expect(iD.osmIsSimpleMultipolygonOuterMember(outer, graph)).to.equal(relation);
    });

    it('returns false if entity is not a way', function() {
        var outer = iD.Node({tags: {'natural':'wood'}}),
            relation = iD.Relation({tags: {type: 'multipolygon'},
                members: [{id: outer.id, role: 'outer'}]}),
            graph = iD.Graph([outer, relation]);
        expect(iD.osmIsSimpleMultipolygonOuterMember(outer, graph)).to.be.false;
    });

    it('returns false if entity does not have interesting tags', function() {
        var outer = iD.Way({tags: {'tiger:reviewed':'no'}}),
            relation = iD.Relation({tags: {type: 'multipolygon'},
                members: [{id: outer.id, role: 'outer'}]}),
            graph = iD.Graph([outer, relation]);
        expect(iD.osmIsSimpleMultipolygonOuterMember(outer, graph)).to.be.false;
    });

    it('returns false if entity does not have a parent relation', function() {
        var outer = iD.Way({tags: {'natural':'wood'}}),
            graph = iD.Graph([outer]);
        expect(iD.osmIsSimpleMultipolygonOuterMember(outer, graph)).to.be.false;
    });

    it('returns false if the parent is not a multipolygon', function() {
        var outer = iD.Way({tags: {'natural':'wood'}}),
            relation = iD.Relation({tags: {type: 'route'},
                members: [{id: outer.id, role: 'outer'}]}),
            graph = iD.Graph([outer, relation]);
        expect(iD.osmIsSimpleMultipolygonOuterMember(outer, graph)).to.be.false;
    });

    it('returns false if the parent has interesting tags', function() {
        var outer = iD.Way({tags: {'natural':'wood'}}),
            relation = iD.Relation({tags: {natural: 'wood', type: 'multipolygon'},
                members: [{id: outer.id, role: 'outer'}]}),
            graph = iD.Graph([outer, relation]);
        expect(iD.osmIsSimpleMultipolygonOuterMember(outer, graph)).to.be.false;
    });

    it('returns the parent relation of a simple multipolygon outer, ignoring uninteresting parent tags', function() {
        var outer = iD.Way({tags: {'natural':'wood'}}),
            relation = iD.Relation({tags: {'tiger:reviewed':'no', type: 'multipolygon'},
                members: [{id: outer.id, role: 'outer'}]}),
            graph = iD.Graph([outer, relation]);
        expect(iD.osmIsSimpleMultipolygonOuterMember(outer, graph)).to.equal(relation);
    });

    it('returns false if the parent has multiple outer ways', function() {
        var outer1 = iD.Way({tags: {'natural':'wood'}}),
            outer2 = iD.Way({tags: {'natural':'wood'}}),
            relation = iD.Relation({tags: {type: 'multipolygon'},
                members: [{id: outer1.id, role: 'outer'}, {id: outer2.id, role: 'outer'}]}),
            graph = iD.Graph([outer1, outer2, relation]);
        expect(iD.osmIsSimpleMultipolygonOuterMember(outer1, graph)).to.be.false;
        expect(iD.osmIsSimpleMultipolygonOuterMember(outer2, graph)).to.be.false;
    });

    it('returns false if the parent has multiple outer ways, assuming role outer if unspecified', function() {
        var outer1 = iD.Way({tags: {'natural':'wood'}}),
            outer2 = iD.Way({tags: {'natural':'wood'}}),
            relation = iD.Relation({tags: {type: 'multipolygon'},
                members: [{id: outer1.id}, {id: outer2.id}]}),
            graph = iD.Graph([outer1, outer2, relation]);
        expect(iD.osmIsSimpleMultipolygonOuterMember(outer1, graph)).to.be.false;
        expect(iD.osmIsSimpleMultipolygonOuterMember(outer2, graph)).to.be.false;
    });

    it('returns false if the entity is not an outer', function() {
        var inner = iD.Way({tags: {'natural':'wood'}}),
            relation = iD.Relation({tags: {type: 'multipolygon'},
                members: [{id: inner.id, role: 'inner'}]}),
            graph = iD.Graph([inner, relation]);
        expect(iD.osmIsSimpleMultipolygonOuterMember(inner, graph)).to.be.false;
    });
});


describe('iD.osmSimpleMultipolygonOuterMember', function() {
    it('returns the outer member of a simple multipolygon', function() {
        var inner = iD.Way(),
            outer = iD.Way({tags: {'natural':'wood'}}),
            relation = iD.Relation({tags: {type: 'multipolygon'}, members: [
                {id: outer.id, role: 'outer'},
                {id: inner.id, role: 'inner'}]
            }),
            graph = iD.Graph([inner, outer, relation]);

        expect(iD.osmSimpleMultipolygonOuterMember(inner, graph)).to.equal(outer);
        expect(iD.osmSimpleMultipolygonOuterMember(outer, graph)).to.equal(outer);
    });

    it('returns falsy for a complex multipolygon', function() {
        var inner = iD.Way(),
            outer1 = iD.Way({tags: {'natural':'wood'}}),
            outer2 = iD.Way({tags: {'natural':'wood'}}),
            relation = iD.Relation({tags: {type: 'multipolygon'}, members: [
                {id: outer1.id, role: 'outer'},
                {id: outer2.id, role: 'outer'},
                {id: inner.id, role: 'inner'}]
            }),
            graph = iD.Graph([inner, outer1, outer2, relation]);

        expect(iD.osmSimpleMultipolygonOuterMember(inner, graph)).not.to.be.ok;
        expect(iD.osmSimpleMultipolygonOuterMember(outer1, graph)).not.to.be.ok;
        expect(iD.osmSimpleMultipolygonOuterMember(outer2, graph)).not.to.be.ok;
    });

    it('handles incomplete relations', function() {
        var way = iD.Way({id: 'w'}),
            relation = iD.Relation({id: 'r', tags: {type: 'multipolygon'}, members: [
                {id: 'o', role: 'outer'},
                {id: 'w', role: 'inner'}]
            }),
            graph = iD.Graph([way, relation]);

        expect(iD.osmSimpleMultipolygonOuterMember(way, graph)).not.to.be.ok;
    });
});


describe('iD.osmJoinWays', function() {
    it('returns an array of members with nodes properties', function() {
        var node = iD.Node({loc: [0, 0]}),
            way  = iD.Way({nodes: [node.id]}),
            member = {id: way.id, type: 'way'},
            graph = iD.Graph([node, way]),
            result = iD.osmJoinWays([member], graph);

        expect(result.length).to.equal(1);
        expect(result[0].nodes.length).to.equal(1);
        expect(result[0].nodes[0]).to.equal(node);
        expect(result[0].length).to.equal(1);
        expect(result[0][0]).to.equal(member);
    });

    it('returns the members in the correct order', function() {
        // a<===b--->c~~~>d
        var graph = iD.Graph([
            iD.Node({id: 'a', loc: [0, 0]}),
            iD.Node({id: 'b', loc: [0, 0]}),
            iD.Node({id: 'c', loc: [0, 0]}),
            iD.Node({id: 'd', loc: [0, 0]}),
            iD.Way({id: '=', nodes: ['b', 'a']}),
            iD.Way({id: '-', nodes: ['b', 'c']}),
            iD.Way({id: '~', nodes: ['c', 'd']}),
            iD.Relation({id: 'r', members: [
                {id: '-', type: 'way'},
                {id: '~', type: 'way'},
                {id: '=', type: 'way'}
            ]})
        ]);

        var result = iD.osmJoinWays(graph.entity('r').members, graph);
        expect(_.map(result[0], 'id')).to.eql(['=', '-', '~']);
    });

    it('reverses member tags of reversed segements', function() {
        // a --> b <== c
        // Expected result:
        // a --> b --> c
        // tags on === reversed
        var graph = iD.Graph([
                iD.Node({id: 'a'}),
                iD.Node({id: 'b'}),
                iD.Node({id: 'c'}),
                iD.Way({id: '-', nodes: ['a', 'b']}),
                iD.Way({id: '=', nodes: ['c', 'b'], tags: {'oneway': 'yes', 'lanes:forward': 2}})
            ]);

        var result = iD.osmJoinWays([graph.entity('-'), graph.entity('=')], graph);
        expect(result[0][1].tags).to.eql({'oneway': '-1', 'lanes:backward': 2});
    });

    it('ignores non-way members', function() {
        var node = iD.Node({loc: [0, 0]}),
            member = {id: 'n', type: 'node'},
            graph = iD.Graph([node]);
        expect(iD.osmJoinWays([member], graph)).to.eql([]);
    });

    it('ignores incomplete members', function() {
        var member = {id: 'w', type: 'way'},
            graph = iD.Graph();
        expect(iD.osmJoinWays([member], graph)).to.eql([]);
    });
});
